GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu, const GrGLProgramDesc& desc) : INHERITED(gpu, desc) { SkASSERT(!desc.getHeader().fHasVertexCode); SkASSERT(gpu->glCaps().pathRenderingSupport()); SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput); SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput); }
GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu, GrGLUniformManager& uniformManager, const GrGLProgramDesc& desc) : INHERITED(gpu, uniformManager, desc) , fNumTexCoordSets(0) { SkASSERT(!desc.getHeader().fHasVertexCode); SkASSERT(gpu->glCaps().fixedFunctionSupport()); SkASSERT(gpu->glCaps().pathRenderingSupport()); SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput); SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput); }
GrGLProgram* GrGLGpu::ProgramCache::refProgram(const GrGLGpu* gpu, const GrPipeline& pipeline, const GrPrimitiveProcessor& primProc) { #ifdef PROGRAM_CACHE_STATS ++fTotalRequests; #endif // Get GrGLProgramDesc GrGLProgramDesc desc; if (!GrGLProgramDescBuilder::Build(&desc, primProc, pipeline, *gpu->glCaps().glslCaps())) { GrCapsDebugf(gpu->caps(), "Failed to gl program descriptor!\n"); return nullptr; } Entry* entry = nullptr; uint32_t hashIdx = desc.getChecksum(); hashIdx ^= hashIdx >> 16; if (kHashBits <= 8) { hashIdx ^= hashIdx >> 8; }
GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu, GrGLUniformManager* uniformManager, const GrGLProgramDesc& desc) : fDesc(desc) , fGpu(gpu) , fUniformManager(SkRef(uniformManager)) , fFSFeaturesAddedMask(0) , fFSInputs(kVarsPerBlock) , fFSOutputs(kMaxFSOutputs) , fUniforms(kVarsPerBlock) , fSetupFragPosition(false) , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) , fHasCustomColorOutput(false) , fHasSecondaryOutput(false) { }
GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu, const GrGLProgramDesc& desc) : fHasVertexShader(false) , fTexCoordSetCnt(0) , fProgramID(0) , fDesc(desc) , fGpu(gpu) , fFSFeaturesAddedMask(0) , fFSInputs(kVarsPerBlock) , fFSOutputs(kMaxFSOutputs) , fUniforms(kVarsPerBlock) , fSetupFragPosition(false) , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) , fHasCustomColorOutput(false) , fHasSecondaryOutput(false) { }
bool GrGLShaderBuilder::GenProgram(GrGpuGL* gpu, GrGLUniformManager* uman, const GrGLProgramDesc& desc, const GrEffectStage* inColorStages[], const GrEffectStage* inCoverageStages[], GenProgramOutput* output) { SkAutoTDelete<GrGLShaderBuilder> builder; if (desc.getHeader().fHasVertexCode ||!gpu->shouldUseFixedFunctionTexturing()) { builder.reset(SkNEW_ARGS(GrGLFullShaderBuilder, (gpu, uman, desc))); } else { builder.reset(SkNEW_ARGS(GrGLFragmentOnlyShaderBuilder, (gpu, uman, desc))); } if (builder->genProgram(inColorStages, inCoverageStages)) { *output = builder->getOutput(); return true; } return false; }
bool GrGpuGL::programUnitTest(int maxStages) { GrTextureDesc dummyDesc; dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit; dummyDesc.fConfig = kSkia8888_GrPixelConfig; dummyDesc.fWidth = 34; dummyDesc.fHeight = 18; SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0)); dummyDesc.fFlags = kNone_GrTextureFlags; dummyDesc.fConfig = kAlpha_8_GrPixelConfig; dummyDesc.fWidth = 16; dummyDesc.fHeight = 22; SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0)); if (!dummyTexture1 || ! dummyTexture2) { return false; } static const int NUM_TESTS = 512; SkRandom random; for (int t = 0; t < NUM_TESTS; ++t) { #if 0 GrPrintf("\nTest Program %d\n-------------\n", t); static const int stop = -1; if (t == stop) { int breakpointhere = 9; } #endif GrGLProgramDesc pdesc; int currAttribIndex = 1; // we need to always leave room for position int currTextureCoordSet = 0; GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; int numStages = random.nextULessThan(maxStages + 1); int numColorStages = random.nextULessThan(numStages + 1); int numCoverageStages = numStages - numColorStages; SkAutoSTMalloc<8, const GrFragmentStage*> stages(numStages); bool usePathRendering = this->glCaps().pathRenderingSupport() && random.nextBool(); GrGpu::DrawType drawType = usePathRendering ? GrGpu::kDrawPath_DrawType : GrGpu::kDrawPoints_DrawType; SkAutoTDelete<GrGeometryStage> geometryProcessor; bool hasGeometryProcessor = usePathRendering ? false : random.nextBool(); if (hasGeometryProcessor) { while (true) { SkAutoTUnref<const GrGeometryProcessor> effect( GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(&random, this->getContext(), *this->caps(), dummyTextures)); SkASSERT(effect); // Only geometryProcessor can use vertex shader GrGeometryStage* stage = SkNEW_ARGS(GrGeometryStage, (effect.get())); geometryProcessor.reset(stage); // we have to set dummy vertex attribs const GrGeometryProcessor::VertexAttribArray& v = effect->getVertexAttribs(); int numVertexAttribs = v.count(); SkASSERT(GrGeometryProcessor::kMaxVertexAttribs == 2 && GrGeometryProcessor::kMaxVertexAttribs >= numVertexAttribs); size_t runningStride = GrVertexAttribTypeSize(genericVertexAttribs[0].fType); for (int i = 0; i < numVertexAttribs; i++) { genericVertexAttribs[i + 1].fOffset = runningStride; genericVertexAttribs[i + 1].fType = convert_sltype_to_attribtype(v[i].getType()); runningStride += GrVertexAttribTypeSize(genericVertexAttribs[i + 1].fType); } // update the vertex attributes with the ds GrDrawState* ds = this->drawState(); ds->setVertexAttribs<genericVertexAttribs>(numVertexAttribs + 1, runningStride); currAttribIndex = numVertexAttribs + 1; break; } } for (int s = 0; s < numStages;) { SkAutoTUnref<const GrFragmentProcessor> effect( GrProcessorTestFactory<GrFragmentProcessor>::CreateStage( &random, this->getContext(), *this->caps(), dummyTextures)); SkASSERT(effect); // If adding this effect would exceed the max texture coord set count then generate a // new random effect. if (usePathRendering && this->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode) {; int numTransforms = effect->numTransforms(); if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) { continue; } currTextureCoordSet += numTransforms; } GrFragmentStage* stage = SkNEW_ARGS(GrFragmentStage, (effect.get())); stages[s] = stage; ++s; } const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1]; if (!pdesc.setRandom(&random, this, dummyTextures[0]->asRenderTarget(), dstTexture, geometryProcessor.get(), stages.get(), numColorStages, numCoverageStages, currAttribIndex, drawType)) { return false; } SkAutoTUnref<GrOptDrawState> optState(GrOptDrawState::Create(this->getDrawState(), *this->caps(), drawType)); SkAutoTUnref<GrGLProgram> program( GrGLProgramBuilder::CreateProgram(*optState, pdesc, drawType, geometryProcessor, stages, stages + numColorStages, this)); for (int s = 0; s < numStages; ++s) { SkDELETE(stages[s]); } if (NULL == program.get()) { return false; } // We have to reset the drawstate because we might have added a gp this->drawState()->reset(); } return true; }
bool GrGpuGL::programUnitTest(int maxStages) { GrTextureDesc dummyDesc; dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit; dummyDesc.fConfig = kSkia8888_GrPixelConfig; dummyDesc.fWidth = 34; dummyDesc.fHeight = 18; SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0)); dummyDesc.fFlags = kNone_GrTextureFlags; dummyDesc.fConfig = kAlpha_8_GrPixelConfig; dummyDesc.fWidth = 16; dummyDesc.fHeight = 22; SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0)); static const int NUM_TESTS = 512; SkRandom random; for (int t = 0; t < NUM_TESTS; ++t) { #if 0 GrPrintf("\nTest Program %d\n-------------\n", t); static const int stop = -1; if (t == stop) { int breakpointhere = 9; } #endif GrGLProgramDesc pdesc; int currAttribIndex = 1; // we need to always leave room for position int currTextureCoordSet = 0; int attribIndices[2] = { 0, 0 }; GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; int numStages = random.nextULessThan(maxStages + 1); int numColorStages = random.nextULessThan(numStages + 1); int numCoverageStages = numStages - numColorStages; SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages); bool useFixedFunctionTexturing = this->shouldUseFixedFunctionTexturing(); for (int s = 0; s < numStages;) { SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage( &random, this->getContext(), *this->caps(), dummyTextures)); SkASSERT(effect); int numAttribs = (*effect)->numVertexAttribs(); // If adding this effect would exceed the max attrib count then generate a // new random effect. if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) { continue; } // If adding this effect would exceed the max texture coord set count then generate a // new random effect. if (useFixedFunctionTexturing && !(*effect)->hasVertexCode()) { int numTransforms = (*effect)->numTransforms(); if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) { continue; } currTextureCoordSet += numTransforms; } useFixedFunctionTexturing = useFixedFunctionTexturing && !(*effect)->hasVertexCode(); for (int i = 0; i < numAttribs; ++i) { attribIndices[i] = currAttribIndex++; } GrEffectStage* stage = SkNEW_ARGS(GrEffectStage, (effect.get(), attribIndices[0], attribIndices[1])); stages[s] = stage; ++s; } const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1]; pdesc.setRandom(&random, this, dummyTextures[0]->asRenderTarget(), dstTexture, stages.get(), numColorStages, numCoverageStages, currAttribIndex); SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this, pdesc, stages, stages + numColorStages)); for (int s = 0; s < numStages; ++s) { SkDELETE(stages[s]); } if (NULL == program.get()) { return false; } } return true; }
bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc, const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, const GrGLGpu* gpu, const GrBatchTracker& batchTracker) { // The descriptor is used as a cache key. Thus when a field of the // descriptor will not affect program generation (because of the attribute // bindings in use or other descriptor field settings) it should be set // to a canonical value to avoid duplicate programs with different keys. GrGLProgramDesc* glDesc = (GrGLProgramDesc*) desc; GR_STATIC_ASSERT(0 == kProcessorKeysOffset % sizeof(uint32_t)); // Make room for everything up to the effect keys. glDesc->key().reset(); glDesc->key().push_back_n(kProcessorKeysOffset); GrProcessorKeyBuilder b(&glDesc->key()); primProc.getGLProcessorKey(batchTracker, gpu->glCaps(), &b); if (!get_meta_key(primProc, gpu->glCaps(), 0, &b)) { glDesc->key().reset(); return false; } for (int s = 0; s < pipeline.numFragmentStages(); ++s) { const GrPendingFragmentStage& fps = pipeline.getFragmentStage(s); const GrFragmentProcessor& fp = *fps.processor(); fp.getGLProcessorKey(gpu->glCaps(), &b); if (!get_meta_key(fp, gpu->glCaps(), primProc.getTransformKey(fp.coordTransforms()), &b)) { glDesc->key().reset(); return false; } } const GrXferProcessor& xp = *pipeline.getXferProcessor(); xp.getGLProcessorKey(gpu->glCaps(), &b); if (!get_meta_key(xp, gpu->glCaps(), 0, &b)) { glDesc->key().reset(); return false; } // --------DO NOT MOVE HEADER ABOVE THIS LINE-------------------------------------------------- // Because header is a pointer into the dynamic array, we can't push any new data into the key // below here. KeyHeader* header = glDesc->atOffset<KeyHeader, kHeaderOffset>(); // make sure any padding in the header is zeroed. memset(header, 0, kHeaderSize); if (pipeline.readsFragPosition()) { header->fFragPosKey = GrGLFragmentShaderBuilder::KeyForFragmentPosition(pipeline.getRenderTarget(), gpu->glCaps()); } else { header->fFragPosKey = 0; } header->fColorEffectCnt = pipeline.numColorFragmentStages(); header->fCoverageEffectCnt = pipeline.numCoverageFragmentStages(); glDesc->finalize(); return true; }
bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc, const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, const GrGLSLCaps& glslCaps) { // The descriptor is used as a cache key. Thus when a field of the // descriptor will not affect program generation (because of the attribute // bindings in use or other descriptor field settings) it should be set // to a canonical value to avoid duplicate programs with different keys. GrGLProgramDesc* glDesc = (GrGLProgramDesc*) desc; GR_STATIC_ASSERT(0 == kProcessorKeysOffset % sizeof(uint32_t)); // Make room for everything up to the effect keys. glDesc->key().reset(); glDesc->key().push_back_n(kProcessorKeysOffset); GrProcessorKeyBuilder b(&glDesc->key()); primProc.getGLSLProcessorKey(glslCaps, &b); if (!gen_meta_key(primProc, glslCaps, 0, &b)) { glDesc->key().reset(); return false; } GrProcessor::RequiredFeatures requiredFeatures = primProc.requiredFeatures(); for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) { const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i); if (!gen_frag_proc_and_meta_keys(primProc, fp, glslCaps, &b)) { glDesc->key().reset(); return false; } requiredFeatures |= fp.requiredFeatures(); } const GrXferProcessor& xp = pipeline.getXferProcessor(); xp.getGLSLProcessorKey(glslCaps, &b); if (!gen_meta_key(xp, glslCaps, 0, &b)) { glDesc->key().reset(); return false; } requiredFeatures |= xp.requiredFeatures(); // --------DO NOT MOVE HEADER ABOVE THIS LINE-------------------------------------------------- // Because header is a pointer into the dynamic array, we can't push any new data into the key // below here. KeyHeader* header = glDesc->atOffset<KeyHeader, kHeaderOffset>(); // make sure any padding in the header is zeroed. memset(header, 0, kHeaderSize); GrRenderTarget* rt = pipeline.getRenderTarget(); if (requiredFeatures & (GrProcessor::kFragmentPosition_RequiredFeature | GrProcessor::kSampleLocations_RequiredFeature)) { header->fSurfaceOriginKey = GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(rt->origin()); } else { header->fSurfaceOriginKey = 0; } if (requiredFeatures & GrProcessor::kSampleLocations_RequiredFeature) { SkASSERT(pipeline.isHWAntialiasState()); header->fSamplePatternKey = rt->renderTargetPriv().getMultisampleSpecs(pipeline.getStencil()).fUniqueID; } else { header->fSamplePatternKey = 0; } header->fOutputSwizzle = glslCaps.configOutputSwizzle(rt->config()).asKey(); if (pipeline.ignoresCoverage()) { header->fIgnoresCoverage = 1; } else { header->fIgnoresCoverage = 0; } header->fSnapVerticesToPixelCenters = pipeline.snapVerticesToPixelCenters(); header->fColorEffectCnt = pipeline.numColorFragmentProcessors(); header->fCoverageEffectCnt = pipeline.numCoverageFragmentProcessors(); glDesc->finalize(); return true; }
GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu, GrGLUniformManager& uniformManager, const GrGLProgramDesc& desc) : fGpu(gpu) , fUniformManager(uniformManager) , fFSFeaturesAddedMask(0) , fFSInputs(kVarsPerBlock) , fFSOutputs(kMaxFSOutputs) , fUniforms(kVarsPerBlock) , fSetupFragPosition(false) , fHasCustomColorOutput(false) , fHasSecondaryOutput(false) , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) { const GrGLProgramDesc::KeyHeader& header = desc.getHeader(); // Emit code to read the dst copy textue if necessary. if (kNoDstRead_DstReadKey != header.fDstReadKey && GrGLCaps::kNone_FBFetchType == fGpu->glCaps().fbFetchType()) { bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey); const char* dstCopyTopLeftName; const char* dstCopyCoordScaleName; uint32_t configMask; if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { configMask = kA_GrColorComponentFlag; } else { configMask = kRGBA_GrColorComponentFlags; } fDstCopySamplerUniform = this->addUniform(kFragment_Visibility, kSampler2D_GrSLType, "DstCopySampler"); fDstCopyTopLeftUniform = this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyUpperLeft", &dstCopyTopLeftName); fDstCopyScaleUniform = this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyCoordScale", &dstCopyCoordScaleName); const char* fragPos = this->fragmentPosition(); this->fsCodeAppend("\t// Read color from copy of the destination.\n"); this->fsCodeAppendf("\tvec2 _dstTexCoord = (%s.xy - %s) * %s;\n", fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); if (!topDown) { this->fsCodeAppend("\t_dstTexCoord.y = 1.0 - _dstTexCoord.y;\n"); } this->fsCodeAppendf("\tvec4 %s = ", kDstCopyColorName); append_texture_lookup(&fFSCode, fGpu, this->getUniformCStr(fDstCopySamplerUniform), "_dstTexCoord", configMask, "rgba"); this->fsCodeAppend(";\n\n"); } if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) { const char* name; fColorUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Color", &name); fInputColor = GrGLSLExpr4(name); } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fColorInput) { fInputColor = GrGLSLExpr4(1); } else if (GrGLProgramDesc::kTransBlack_ColorInput == header.fColorInput) { fInputColor = GrGLSLExpr4(0); } if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) { const char* name; fCoverageUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Coverage", &name); fInputCoverage = GrGLSLExpr4(name); } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput) { fInputCoverage = GrGLSLExpr4(1); } else if (GrGLProgramDesc::kTransBlack_ColorInput == header.fCoverageInput) { fInputCoverage = GrGLSLExpr4(0); } if (k110_GrGLSLGeneration != fGpu->glslGeneration()) { fFSOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier, declared_color_output_name()); fHasCustomColorOutput = true; } }