void GrGLVertexShaderBuilder::bindProgramLocations(GrGLuint programId) { const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader(); GrGpuGL* gpu = fProgramBuilder->gpu(); // Bind the attrib locations to same values for all shaders SkASSERT(-1 != header.fPositionAttributeIndex); GL_CALL(BindAttribLocation(programId, header.fPositionAttributeIndex, fPositionVar->c_str())); if (-1 != header.fLocalCoordAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fLocalCoordAttributeIndex, fLocalCoordsVar->c_str())); } if (-1 != header.fColorAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fColorAttributeIndex, color_attribute_name())); } if (-1 != header.fCoverageAttributeIndex) { GL_CALL(BindAttribLocation(programId, header.fCoverageAttributeIndex, coverage_attribute_name())); } // We pull the current state of attributes off of drawstate's optimized state and bind them in // order. This assumes that the drawState has not changed since we called flushGraphicsState() // higher up in the stack. const GrDrawTargetCaps* caps = fProgramBuilder->gpu()->caps(); const GrDrawState& drawState = *fProgramBuilder->gpu()->drawState(); SkAutoTUnref<GrOptDrawState> optState(drawState.createOptState(*caps)); const GrVertexAttrib* vaPtr = optState->getVertexAttribs(); const int vaCount = optState->getVertexAttribCount(); int i = fEffectAttribOffset; for (int index = 0; index < vaCount; index++) { if (kGeometryProcessor_GrVertexAttribBinding != vaPtr[index].fBinding) { continue; } SkASSERT(index != header.fPositionAttributeIndex && index != header.fLocalCoordAttributeIndex && index != header.fColorAttributeIndex && index != header.fCoverageAttributeIndex); // We should never find another effect attribute if we have bound everything SkASSERT(i < fInputs.count()); GL_CALL(BindAttribLocation(programId, index, fInputs[i].c_str())); i++; } // Make sure we bound everything SkASSERT(fInputs.count() == i); }
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; }