GrGpuGL_program.cpp revision 288d9549b42a4eb934e814790f2b7a81f017a9c5
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrGpuGL.h"
9
10#include "GrCustomStage.h"
11#include "GrGLProgramStage.h"
12#include "GrGpuVertex.h"
13
14typedef GrGLUniformManager::UniformHandle UniformHandle;
15static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
16
17#define SKIP_CACHE_CHECK    true
18#define GR_UINT32_MAX   static_cast<uint32_t>(-1)
19
20GrGpuGL::ProgramCache::ProgramCache(const GrGLContextInfo& gl)
21    : fCount(0)
22    , fCurrLRUStamp(0)
23    , fGL(gl) {
24}
25
26void GrGpuGL::ProgramCache::abandon() {
27    for (int i = 0; i < fCount; ++i) {
28        GrAssert(NULL != fEntries[i].fProgram.get());
29        fEntries[i].fProgram->abandon();
30        fEntries[i].fProgram.reset(NULL);
31    }
32    fCount = 0;
33}
34
35GrGLProgram* GrGpuGL::ProgramCache::getProgram(const ProgramDesc& desc,
36                                               const GrCustomStage** stages) {
37    Entry newEntry;
38    newEntry.fKey.setKeyData(desc.asKey());
39
40    Entry* entry = fHashCache.find(newEntry.fKey);
41    if (NULL == entry) {
42        newEntry.fProgram.reset(GrGLProgram::Create(fGL, desc, stages));
43        if (NULL == newEntry.fProgram.get()) {
44            return NULL;
45        }
46        if (fCount < kMaxEntries) {
47            entry = fEntries + fCount;
48            ++fCount;
49        } else {
50            GrAssert(kMaxEntries == fCount);
51            entry = fEntries;
52            for (int i = 1; i < kMaxEntries; ++i) {
53                if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
54                    entry = fEntries + i;
55                }
56            }
57            fHashCache.remove(entry->fKey, entry);
58        }
59        *entry = newEntry;
60        fHashCache.insert(entry->fKey, entry);
61    }
62
63    entry->fLRUStamp = fCurrLRUStamp;
64    if (GR_UINT32_MAX == fCurrLRUStamp) {
65        // wrap around! just trash our LRU, one time hit.
66        for (int i = 0; i < fCount; ++i) {
67            fEntries[i].fLRUStamp = 0;
68        }
69    }
70    ++fCurrLRUStamp;
71    return entry->fProgram;
72}
73
74////////////////////////////////////////////////////////////////////////////////
75
76void GrGpuGL::abandonResources(){
77    INHERITED::abandonResources();
78    fProgramCache->abandon();
79    fHWProgramID = 0;
80}
81
82////////////////////////////////////////////////////////////////////////////////
83
84#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
85
86void GrGpuGL::flushViewMatrix(DrawType type) {
87    const GrGLRenderTarget* rt = static_cast<const GrGLRenderTarget*>(this->getDrawState().getRenderTarget());
88    SkISize viewportSize;
89    const GrGLIRect& viewport = rt->getViewport();
90    viewportSize.set(viewport.fWidth, viewport.fHeight);
91
92    const GrMatrix& vm = this->getDrawState().getViewMatrix();
93
94    if (kStencilPath_DrawType == type) {
95        if (fHWPathMatrixState.fViewMatrix != vm ||
96            fHWPathMatrixState.fRTSize != viewportSize) {
97            // rescale the coords from skia's "device" coords to GL's normalized coords,
98            // and perform a y-flip.
99            GrMatrix m;
100            m.setScale(GrIntToScalar(2) / rt->width(), GrIntToScalar(-2) / rt->height());
101            m.postTranslate(-GR_Scalar1, GR_Scalar1);
102            m.preConcat(vm);
103
104            // GL wants a column-major 4x4.
105            GrGLfloat mv[]  = {
106                // col 0
107                GrScalarToFloat(m[GrMatrix::kMScaleX]),
108                GrScalarToFloat(m[GrMatrix::kMSkewY]),
109                0,
110                GrScalarToFloat(m[GrMatrix::kMPersp0]),
111
112                // col 1
113                GrScalarToFloat(m[GrMatrix::kMSkewX]),
114                GrScalarToFloat(m[GrMatrix::kMScaleY]),
115                0,
116                GrScalarToFloat(m[GrMatrix::kMPersp1]),
117
118                // col 2
119                0, 0, 0, 0,
120
121                // col3
122                GrScalarToFloat(m[GrMatrix::kMTransX]),
123                GrScalarToFloat(m[GrMatrix::kMTransY]),
124                0.0f,
125                GrScalarToFloat(m[GrMatrix::kMPersp2])
126            };
127            GL_CALL(MatrixMode(GR_GL_PROJECTION));
128            GL_CALL(LoadMatrixf(mv));
129            fHWPathMatrixState.fViewMatrix = vm;
130            fHWPathMatrixState.fRTSize = viewportSize;
131        }
132    } else if (!fCurrentProgram->fViewMatrix.cheapEqualTo(vm) ||
133               fCurrentProgram->fViewportSize != viewportSize) {
134        GrMatrix m;
135        m.setAll(
136            GrIntToScalar(2) / viewportSize.fWidth, 0, -GR_Scalar1,
137            0,-GrIntToScalar(2) / viewportSize.fHeight, GR_Scalar1,
138            0, 0, GrMatrix::I()[8]);
139        m.setConcat(m, vm);
140
141        // ES doesn't allow you to pass true to the transpose param,
142        // so do our own transpose
143        GrGLfloat mt[]  = {
144            GrScalarToFloat(m[GrMatrix::kMScaleX]),
145            GrScalarToFloat(m[GrMatrix::kMSkewY]),
146            GrScalarToFloat(m[GrMatrix::kMPersp0]),
147            GrScalarToFloat(m[GrMatrix::kMSkewX]),
148            GrScalarToFloat(m[GrMatrix::kMScaleY]),
149            GrScalarToFloat(m[GrMatrix::kMPersp1]),
150            GrScalarToFloat(m[GrMatrix::kMTransX]),
151            GrScalarToFloat(m[GrMatrix::kMTransY]),
152            GrScalarToFloat(m[GrMatrix::kMPersp2])
153        };
154        fCurrentProgram->fUniformManager.setMatrix3f(fCurrentProgram->fUniforms.fViewMatrixUni, mt);
155        fCurrentProgram->fViewMatrix = vm;
156        fCurrentProgram->fViewportSize = viewportSize;
157    }
158}
159
160///////////////////////////////////////////////////////////////////////////////
161
162// helpers for texture matrices
163
164void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture,
165                                  GrMatrix* matrix) {
166    GrAssert(NULL != texture);
167    GrAssert(NULL != matrix);
168    GrGLTexture::Orientation orientation = texture->orientation();
169    if (GrGLTexture::kBottomUp_Orientation == orientation) {
170        GrMatrix invY;
171        invY.setAll(GR_Scalar1, 0,           0,
172                    0,          -GR_Scalar1, GR_Scalar1,
173                    0,          0,           GrMatrix::I()[8]);
174        matrix->postConcat(invY);
175    } else {
176        GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
177    }
178}
179
180int GrGpuGL::TextureMatrixOptFlags(const GrGLTexture* texture,
181                                   const GrSamplerState& sampler) {
182    GrAssert(NULL != texture);
183    GrMatrix matrix;
184    sampler.getTotalMatrix(&matrix);
185
186    bool canBeIndentity = GrGLTexture::kTopDown_Orientation == texture->orientation();
187
188    if (canBeIndentity && matrix.isIdentity()) {
189        return GrGLProgram::StageDesc::kIdentityMatrix_OptFlagBit;
190    } else if (!matrix.hasPerspective()) {
191        return GrGLProgram::StageDesc::kNoPerspective_OptFlagBit;
192    }
193    return 0;
194}
195
196///////////////////////////////////////////////////////////////////////////////
197
198void GrGpuGL::flushTextureMatrix(int s) {
199    const GrDrawState& drawState = this->getDrawState();
200
201    // FIXME: Still assuming only a single texture per custom stage
202    const GrCustomStage* stage = drawState.getSampler(s).getCustomStage();
203    const GrGLTexture* texture = static_cast<const GrGLTexture*>(stage->texture(0));
204    if (NULL != texture) {
205
206        bool orientationChange = fCurrentProgram->fTextureOrientation[s] !=
207                                 texture->orientation();
208
209        UniformHandle matrixUni = fCurrentProgram->fUniforms.fStages[s].fTextureMatrixUni;
210
211        const GrMatrix& hwMatrix = fCurrentProgram->fTextureMatrices[s];
212        GrMatrix samplerMatrix;
213        drawState.getSampler(s).getTotalMatrix(&samplerMatrix);
214
215        if (kInvalidUniformHandle != matrixUni &&
216            (orientationChange || !hwMatrix.cheapEqualTo(samplerMatrix))) {
217
218            GrMatrix m = samplerMatrix;
219            AdjustTextureMatrix(texture, &m);
220
221            // ES doesn't allow you to pass true to the transpose param,
222            // so do our own transpose
223            GrGLfloat mt[]  = {
224                GrScalarToFloat(m[GrMatrix::kMScaleX]),
225                GrScalarToFloat(m[GrMatrix::kMSkewY]),
226                GrScalarToFloat(m[GrMatrix::kMPersp0]),
227                GrScalarToFloat(m[GrMatrix::kMSkewX]),
228                GrScalarToFloat(m[GrMatrix::kMScaleY]),
229                GrScalarToFloat(m[GrMatrix::kMPersp1]),
230                GrScalarToFloat(m[GrMatrix::kMTransX]),
231                GrScalarToFloat(m[GrMatrix::kMTransY]),
232                GrScalarToFloat(m[GrMatrix::kMPersp2])
233            };
234
235            fCurrentProgram->fUniformManager.setMatrix3f(matrixUni, mt);
236            fCurrentProgram->fTextureMatrices[s] = samplerMatrix;
237        }
238
239        fCurrentProgram->fTextureOrientation[s] = texture->orientation();
240    }
241}
242
243void GrGpuGL::flushColorMatrix() {
244    UniformHandle matrixUni = fCurrentProgram->fUniforms.fColorMatrixUni;
245    UniformHandle vecUni = fCurrentProgram->fUniforms.fColorMatrixVecUni;
246    if (kInvalidUniformHandle != matrixUni && kInvalidUniformHandle != vecUni) {
247        const float* m = this->getDrawState().getColorMatrix();
248        GrGLfloat mt[]  = {
249            m[0], m[5], m[10], m[15],
250            m[1], m[6], m[11], m[16],
251            m[2], m[7], m[12], m[17],
252            m[3], m[8], m[13], m[18],
253        };
254        static float scale = 1.0f / 255.0f;
255        GrGLfloat vec[] = {
256            m[4] * scale, m[9] * scale, m[14] * scale, m[19] * scale,
257        };
258        fCurrentProgram->fUniformManager.setMatrix4f(matrixUni, mt);
259        fCurrentProgram->fUniformManager.set4fv(vecUni, 0, 1, vec);
260    }
261}
262
263void GrGpuGL::flushColor(GrColor color) {
264    const ProgramDesc& desc = fCurrentProgram->getDesc();
265    const GrDrawState& drawState = this->getDrawState();
266
267    if (this->getVertexLayout() & kColor_VertexLayoutBit) {
268        // color will be specified per-vertex as an attribute
269        // invalidate the const vertex attrib color
270        fHWConstAttribColor = GrColor_ILLEGAL;
271    } else {
272        switch (desc.fColorInput) {
273            case ProgramDesc::kAttribute_ColorInput:
274                if (fHWConstAttribColor != color) {
275                    // OpenGL ES only supports the float varieties of glVertexAttrib
276                    GrGLfloat c[4];
277                    GrColorToRGBAFloat(color, c);
278                    GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
279                    fHWConstAttribColor = color;
280                }
281                break;
282            case ProgramDesc::kUniform_ColorInput:
283                if (fCurrentProgram->fColor != color) {
284                    // OpenGL ES doesn't support unsigned byte varieties of glUniform
285                    GrGLfloat c[4];
286                    GrColorToRGBAFloat(color, c);
287                    GrAssert(kInvalidUniformHandle !=  fCurrentProgram->fUniforms.fColorUni);
288                    fCurrentProgram->fUniformManager.set4fv(fCurrentProgram->fUniforms.fColorUni,
289                                                            0, 1, c);
290                    fCurrentProgram->fColor = color;
291                }
292                break;
293            case ProgramDesc::kSolidWhite_ColorInput:
294            case ProgramDesc::kTransBlack_ColorInput:
295                break;
296            default:
297                GrCrash("Unknown color type.");
298        }
299    }
300    UniformHandle filterColorUni = fCurrentProgram->fUniforms.fColorFilterUni;
301    if (kInvalidUniformHandle != filterColorUni &&
302        fCurrentProgram->fColorFilterColor != drawState.getColorFilterColor()) {
303        GrGLfloat c[4];
304        GrColorToRGBAFloat(drawState.getColorFilterColor(), c);
305        fCurrentProgram->fUniformManager.set4fv(filterColorUni, 0, 1, c);
306        fCurrentProgram->fColorFilterColor = drawState.getColorFilterColor();
307    }
308}
309
310void GrGpuGL::flushCoverage(GrColor coverage) {
311    const ProgramDesc& desc = fCurrentProgram->getDesc();
312    // const GrDrawState& drawState = this->getDrawState();
313
314
315    if (this->getVertexLayout() & kCoverage_VertexLayoutBit) {
316        // coverage will be specified per-vertex as an attribute
317        // invalidate the const vertex attrib coverage
318        fHWConstAttribCoverage = GrColor_ILLEGAL;
319    } else {
320        switch (desc.fCoverageInput) {
321            case ProgramDesc::kAttribute_ColorInput:
322                if (fHWConstAttribCoverage != coverage) {
323                    // OpenGL ES only supports the float varieties of
324                    // glVertexAttrib
325                    GrGLfloat c[4];
326                    GrColorToRGBAFloat(coverage, c);
327                    GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(),
328                                            c));
329                    fHWConstAttribCoverage = coverage;
330                }
331                break;
332            case ProgramDesc::kUniform_ColorInput:
333                if (fCurrentProgram->fCoverage != coverage) {
334                    // OpenGL ES doesn't support unsigned byte varieties of
335                    // glUniform
336                    GrGLfloat c[4];
337                    GrColorToRGBAFloat(coverage, c);
338                    GrAssert(kInvalidUniformHandle !=  fCurrentProgram->fUniforms.fCoverageUni);
339                    fCurrentProgram->fUniformManager.set4fv(fCurrentProgram->fUniforms.fCoverageUni,
340                                                            0, 1, c);
341                    fCurrentProgram->fCoverage = coverage;
342                }
343                break;
344            case ProgramDesc::kSolidWhite_ColorInput:
345            case ProgramDesc::kTransBlack_ColorInput:
346                break;
347            default:
348                GrCrash("Unknown coverage type.");
349        }
350    }
351}
352
353bool GrGpuGL::flushGraphicsState(DrawType type) {
354    const GrDrawState& drawState = this->getDrawState();
355
356    // GrGpu::setupClipAndFlushState should have already checked this
357    // and bailed if not true.
358    GrAssert(NULL != drawState.getRenderTarget());
359
360    if (kStencilPath_DrawType != type) {
361        this->flushMiscFixedFunctionState();
362
363        GrBlendCoeff srcCoeff;
364        GrBlendCoeff dstCoeff;
365        BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
366        if (kSkipDraw_BlendOptFlag & blendOpts) {
367            return false;
368        }
369
370        const GrCustomStage* customStages [GrDrawState::kNumStages];
371        GrGLProgram::Desc desc;
372        this->buildProgram(kDrawPoints_DrawType == type, blendOpts, dstCoeff, customStages, &desc);
373
374        fCurrentProgram.reset(fProgramCache->getProgram(desc, customStages));
375        if (NULL == fCurrentProgram.get()) {
376            GrAssert(!"Failed to create program!");
377            return false;
378        }
379        fCurrentProgram.get()->ref();
380
381        if (fHWProgramID != fCurrentProgram->fProgramID) {
382            GL_CALL(UseProgram(fCurrentProgram->fProgramID));
383            fHWProgramID = fCurrentProgram->fProgramID;
384        }
385        fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff);
386        this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
387
388        GrColor color;
389        GrColor coverage;
390        if (blendOpts & kEmitTransBlack_BlendOptFlag) {
391            color = 0;
392            coverage = 0;
393        } else if (blendOpts & kEmitCoverage_BlendOptFlag) {
394            color = 0xffffffff;
395            coverage = drawState.getCoverage();
396        } else {
397            color = drawState.getColor();
398            coverage = drawState.getCoverage();
399        }
400        this->flushColor(color);
401        this->flushCoverage(coverage);
402
403        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
404            if (this->isStageEnabled(s)) {
405                this->flushBoundTextureAndParams(s);
406
407                this->flushTextureMatrix(s);
408
409                if (NULL != fCurrentProgram->fProgramStage[s]) {
410                    const GrSamplerState& sampler = this->getDrawState().getSampler(s);
411                    fCurrentProgram->fProgramStage[s]->setData(fCurrentProgram->fUniformManager,
412                                                               *sampler.getCustomStage(),
413                                                               drawState.getRenderTarget(), s);
414                }
415            }
416        }
417        this->flushColorMatrix();
418    }
419    this->flushStencil(type);
420    this->flushViewMatrix(type);
421    this->flushScissor();
422    this->flushAAState(type);
423
424    GrIRect* devRect = NULL;
425    GrIRect devClipBounds;
426    if (drawState.isClipState()) {
427        fClip->getConservativeBounds(drawState.getRenderTarget(),
428                                     &devClipBounds);
429        devRect = &devClipBounds;
430    }
431    // This must come after textures are flushed because a texture may need
432    // to be msaa-resolved (which will modify bound FBO state).
433    this->flushRenderTarget(devRect);
434
435    return true;
436}
437
438#if GR_TEXT_SCALAR_IS_USHORT
439    #define TEXT_COORDS_GL_TYPE          GR_GL_UNSIGNED_SHORT
440    #define TEXT_COORDS_ARE_NORMALIZED   1
441#elif GR_TEXT_SCALAR_IS_FLOAT
442    #define TEXT_COORDS_GL_TYPE          GR_GL_FLOAT
443    #define TEXT_COORDS_ARE_NORMALIZED   0
444#elif GR_TEXT_SCALAR_IS_FIXED
445    #define TEXT_COORDS_GL_TYPE          GR_GL_FIXED
446    #define TEXT_COORDS_ARE_NORMALIZED   0
447#else
448    #error "unknown GR_TEXT_SCALAR type"
449#endif
450
451void GrGpuGL::setupGeometry(int* startVertex,
452                            int* startIndex,
453                            int vertexCount,
454                            int indexCount) {
455
456    int newColorOffset;
457    int newCoverageOffset;
458    int newTexCoordOffsets[GrDrawState::kMaxTexCoords];
459    int newEdgeOffset;
460
461    GrVertexLayout currLayout = this->getVertexLayout();
462
463    GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
464                                            currLayout,
465                                            newTexCoordOffsets,
466                                            &newColorOffset,
467                                            &newCoverageOffset,
468                                            &newEdgeOffset);
469    int oldColorOffset;
470    int oldCoverageOffset;
471    int oldTexCoordOffsets[GrDrawState::kMaxTexCoords];
472    int oldEdgeOffset;
473
474    GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
475                                            fHWGeometryState.fVertexLayout,
476                                            oldTexCoordOffsets,
477                                            &oldColorOffset,
478                                            &oldCoverageOffset,
479                                            &oldEdgeOffset);
480    bool indexed = NULL != startIndex;
481
482    int extraVertexOffset;
483    int extraIndexOffset;
484    this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
485
486    GrGLenum scalarType;
487    bool texCoordNorm;
488    if (currLayout & kTextFormat_VertexLayoutBit) {
489        scalarType = TEXT_COORDS_GL_TYPE;
490        texCoordNorm = SkToBool(TEXT_COORDS_ARE_NORMALIZED);
491    } else {
492        GR_STATIC_ASSERT(GR_SCALAR_IS_FLOAT);
493        scalarType = GR_GL_FLOAT;
494        texCoordNorm = false;
495    }
496
497    size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
498    *startVertex = 0;
499    if (indexed) {
500        *startIndex += extraIndexOffset;
501    }
502
503    // all the Pointers must be set if any of these are true
504    bool allOffsetsChange =  fHWGeometryState.fArrayPtrsDirty ||
505                             vertexOffset != fHWGeometryState.fVertexOffset ||
506                             newStride != oldStride;
507
508    // position and tex coord offsets change if above conditions are true
509    // or the type/normalization changed based on text vs nontext type coords.
510    bool posAndTexChange = allOffsetsChange ||
511                           (((TEXT_COORDS_GL_TYPE != GR_GL_FLOAT) || TEXT_COORDS_ARE_NORMALIZED) &&
512                                (kTextFormat_VertexLayoutBit &
513                                  (fHWGeometryState.fVertexLayout ^ currLayout)));
514
515    if (posAndTexChange) {
516        int idx = GrGLProgram::PositionAttributeIdx();
517        GL_CALL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
518                                  (GrGLvoid*)vertexOffset));
519        fHWGeometryState.fVertexOffset = vertexOffset;
520    }
521
522    for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
523        if (newTexCoordOffsets[t] > 0) {
524            GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
525            int idx = GrGLProgram::TexCoordAttributeIdx(t);
526            if (oldTexCoordOffsets[t] <= 0) {
527                GL_CALL(EnableVertexAttribArray(idx));
528                GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
529                                          newStride, texCoordOffset));
530            } else if (posAndTexChange ||
531                       newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
532                GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
533                                          newStride, texCoordOffset));
534            }
535        } else if (oldTexCoordOffsets[t] > 0) {
536            GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
537        }
538    }
539
540    if (newColorOffset > 0) {
541        GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
542        int idx = GrGLProgram::ColorAttributeIdx();
543        if (oldColorOffset <= 0) {
544            GL_CALL(EnableVertexAttribArray(idx));
545            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
546                                      true, newStride, colorOffset));
547        } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
548            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
549                                      true, newStride, colorOffset));
550        }
551    } else if (oldColorOffset > 0) {
552        GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
553    }
554
555    if (newCoverageOffset > 0) {
556        GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset);
557        int idx = GrGLProgram::CoverageAttributeIdx();
558        if (oldCoverageOffset <= 0) {
559            GL_CALL(EnableVertexAttribArray(idx));
560            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
561                                        true, newStride, coverageOffset));
562        } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) {
563            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
564                                        true, newStride, coverageOffset));
565        }
566    } else if (oldCoverageOffset > 0) {
567        GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx()));
568    }
569
570    if (newEdgeOffset > 0) {
571        GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset);
572        int idx = GrGLProgram::EdgeAttributeIdx();
573        if (oldEdgeOffset <= 0) {
574            GL_CALL(EnableVertexAttribArray(idx));
575            GL_CALL(VertexAttribPointer(idx, 4, scalarType,
576                                        false, newStride, edgeOffset));
577        } else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) {
578            GL_CALL(VertexAttribPointer(idx, 4, scalarType,
579                                        false, newStride, edgeOffset));
580        }
581    } else if (oldEdgeOffset > 0) {
582        GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx()));
583    }
584
585    fHWGeometryState.fVertexLayout = currLayout;
586    fHWGeometryState.fArrayPtrsDirty = false;
587}
588
589namespace {
590
591void setup_custom_stage(GrGLProgram::Desc::StageDesc* stage,
592                        const GrSamplerState& sampler,
593                        const GrGLCaps& caps,
594                        const GrCustomStage** customStages,
595                        GrGLProgram* program, int index) {
596    const GrCustomStage* customStage = sampler.getCustomStage();
597    if (customStage) {
598        const GrProgramStageFactory& factory = customStage->getFactory();
599        stage->fCustomStageKey = factory.glStageKey(*customStage, caps);
600        customStages[index] = customStage;
601    } else {
602        stage->fCustomStageKey = 0;
603        customStages[index] = NULL;
604    }
605}
606
607}
608
609void GrGpuGL::buildProgram(bool isPoints,
610                           BlendOptFlags blendOpts,
611                           GrBlendCoeff dstCoeff,
612                           const GrCustomStage** customStages,
613                           ProgramDesc* desc) {
614    const GrDrawState& drawState = this->getDrawState();
615
616    // This should already have been caught
617    GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts));
618
619    bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
620
621    bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag |
622                                           kEmitCoverage_BlendOptFlag));
623
624    // The descriptor is used as a cache key. Thus when a field of the
625    // descriptor will not affect program generation (because of the vertex
626    // layout in use or other descriptor field settings) it should be set
627    // to a canonical value to avoid duplicate programs with different keys.
628
629    // Must initialize all fields or cache will have false negatives!
630    desc->fVertexLayout = this->getVertexLayout();
631
632    desc->fEmitsPointSize = isPoints;
633
634    bool requiresAttributeColors = !skipColor &&
635                                   SkToBool(desc->fVertexLayout & kColor_VertexLayoutBit);
636    bool requiresAttributeCoverage = !skipCoverage &&
637                                     SkToBool(desc->fVertexLayout & kCoverage_VertexLayoutBit);
638
639    // fColorInput/fCoverageInput records how colors are specified for the.
640    // program. So we strip the bits from the layout to avoid false negatives
641    // when searching for an existing program in the cache.
642    desc->fVertexLayout &= ~(kColor_VertexLayoutBit | kCoverage_VertexLayoutBit);
643
644    desc->fColorFilterXfermode = skipColor ?
645                                SkXfermode::kDst_Mode :
646                                drawState.getColorFilterMode();
647
648    desc->fColorMatrixEnabled = drawState.isStateFlagEnabled(GrDrawState::kColorMatrix_StateBit);
649
650    // no reason to do edge aa or look at per-vertex coverage if coverage is
651    // ignored
652    if (skipCoverage) {
653        desc->fVertexLayout &= ~(kEdge_VertexLayoutBit | kCoverage_VertexLayoutBit);
654    }
655
656    bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
657    bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) ||
658                             (!requiresAttributeColors && 0xffffffff == drawState.getColor());
659    if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) {
660        desc->fColorInput = ProgramDesc::kTransBlack_ColorInput;
661    } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) {
662        desc->fColorInput = ProgramDesc::kSolidWhite_ColorInput;
663    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
664        desc->fColorInput = ProgramDesc::kUniform_ColorInput;
665    } else {
666        desc->fColorInput = ProgramDesc::kAttribute_ColorInput;
667    }
668
669    bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage();
670
671    if (skipCoverage) {
672        desc->fCoverageInput = ProgramDesc::kTransBlack_ColorInput;
673    } else if (covIsSolidWhite) {
674        desc->fCoverageInput = ProgramDesc::kSolidWhite_ColorInput;
675    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) {
676        desc->fCoverageInput = ProgramDesc::kUniform_ColorInput;
677    } else {
678        desc->fCoverageInput = ProgramDesc::kAttribute_ColorInput;
679    }
680
681    int lastEnabledStage = -1;
682
683    if (!skipCoverage && (desc->fVertexLayout &GrDrawTarget::kEdge_VertexLayoutBit)) {
684        desc->fVertexEdgeType = drawState.getVertexEdgeType();
685    } else {
686        // use canonical value when not set to avoid cache misses
687        desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
688    }
689
690    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
691        StageDesc& stage = desc->fStages[s];
692
693        stage.fOptFlags = 0;
694        stage.setEnabled(this->isStageEnabled(s));
695
696        bool skip = s < drawState.getFirstCoverageStage() ? skipColor :
697                                                            skipCoverage;
698
699        if (!skip && stage.isEnabled()) {
700            lastEnabledStage = s;
701            const GrSamplerState& sampler = drawState.getSampler(s);
702            // FIXME: Still assuming one texture per custom stage
703            const GrCustomStage* customStage = drawState.getSampler(s).getCustomStage();
704            const GrGLTexture* texture = static_cast<const GrGLTexture*>(customStage->texture(0));
705            GrMatrix samplerMatrix;
706            sampler.getTotalMatrix(&samplerMatrix);
707            if (NULL != texture) {
708                // We call this helper function rather then simply checking the client-specified
709                // texture matrix. This is because we may have to concat a y-inversion to account
710                // for texture orientation.
711                stage.fOptFlags |= TextureMatrixOptFlags(texture, sampler);
712            }
713
714            setup_custom_stage(&stage, sampler, this->glCaps(), customStages,
715                               fCurrentProgram.get(), s);
716
717        } else {
718            stage.fOptFlags         = 0;
719            stage.fCustomStageKey   = 0;
720            customStages[s] = NULL;
721        }
722    }
723
724    desc->fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
725
726    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
727    // other than pass through values fromthe VS to the FS anyway).
728#if 0 && GR_GL_EXPERIMENTAL_GS
729    desc->fExperimentalGS = this->getCaps().fGeometryShaderSupport;
730#endif
731
732    // We want to avoid generating programs with different "first cov stage" values when they would
733    // compute the same result. We set field in the desc to kNumStages when either there are no
734    // coverage stages or the distinction between coverage and color is immaterial.
735    int firstCoverageStage = GrDrawState::kNumStages;
736    desc->fFirstCoverageStage = GrDrawState::kNumStages;
737    bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage;
738    if (hasCoverage) {
739        firstCoverageStage = drawState.getFirstCoverageStage();
740    }
741
742    // other coverage inputs
743    if (!hasCoverage) {
744        hasCoverage = requiresAttributeCoverage ||
745                      (desc->fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit);
746    }
747
748    if (hasCoverage) {
749        // color filter is applied between color/coverage computation
750        if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
751            desc->fFirstCoverageStage = firstCoverageStage;
752        }
753
754        if (this->getCaps().dualSourceBlendingSupport() &&
755            !(blendOpts & (kEmitCoverage_BlendOptFlag | kCoverageAsAlpha_BlendOptFlag))) {
756            if (kZero_GrBlendCoeff == dstCoeff) {
757                // write the coverage value to second color
758                desc->fDualSrcOutput =  ProgramDesc::kCoverage_DualSrcOutput;
759                desc->fFirstCoverageStage = firstCoverageStage;
760            } else if (kSA_GrBlendCoeff == dstCoeff) {
761                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
762                desc->fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
763                desc->fFirstCoverageStage = firstCoverageStage;
764            } else if (kSC_GrBlendCoeff == dstCoeff) {
765                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
766                desc->fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
767                desc->fFirstCoverageStage = firstCoverageStage;
768            }
769        }
770    }
771}
772