GrGpuGL_program.cpp revision a04e8e842450e606dd938ddae17857849bd504d4
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
180bool GrGpuGL::TextureMatrixIsIdentity(const GrGLTexture* texture,
181                                      const GrSamplerState& sampler) {
182    GrAssert(NULL != texture);
183    if (!sampler.getMatrix().isIdentity()) {
184        return false;
185    }
186    GrGLTexture::Orientation orientation = texture->orientation();
187    if (GrGLTexture::kBottomUp_Orientation == orientation) {
188        return false;
189    } else {
190        GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
191    }
192    return true;
193}
194
195///////////////////////////////////////////////////////////////////////////////
196
197void GrGpuGL::flushTextureMatrix(int s) {
198    const GrDrawState& drawState = this->getDrawState();
199
200    // FIXME: Still assuming only a single texture per custom stage
201    const GrCustomStage* stage = drawState.getSampler(s).getCustomStage();
202    const GrGLTexture* texture = static_cast<const GrGLTexture*>(stage->texture(0));
203    if (NULL != texture) {
204
205        bool orientationChange = fCurrentProgram->fTextureOrientation[s] !=
206                                 texture->orientation();
207
208        UniformHandle matrixUni = fCurrentProgram->fUniforms.fStages[s].fTextureMatrixUni;
209
210        const GrMatrix& hwMatrix = fCurrentProgram->fTextureMatrices[s];
211        const GrMatrix& samplerMatrix = drawState.getSampler(s).getMatrix();
212
213        if (kInvalidUniformHandle != matrixUni &&
214            (orientationChange || !hwMatrix.cheapEqualTo(samplerMatrix))) {
215
216            GrMatrix m = samplerMatrix;
217            AdjustTextureMatrix(texture, &m);
218
219            // ES doesn't allow you to pass true to the transpose param,
220            // so do our own transpose
221            GrGLfloat mt[]  = {
222                GrScalarToFloat(m[GrMatrix::kMScaleX]),
223                GrScalarToFloat(m[GrMatrix::kMSkewY]),
224                GrScalarToFloat(m[GrMatrix::kMPersp0]),
225                GrScalarToFloat(m[GrMatrix::kMSkewX]),
226                GrScalarToFloat(m[GrMatrix::kMScaleY]),
227                GrScalarToFloat(m[GrMatrix::kMPersp1]),
228                GrScalarToFloat(m[GrMatrix::kMTransX]),
229                GrScalarToFloat(m[GrMatrix::kMTransY]),
230                GrScalarToFloat(m[GrMatrix::kMPersp2])
231            };
232
233            fCurrentProgram->fUniformManager.setMatrix3f(matrixUni, mt);
234            fCurrentProgram->fTextureMatrices[s] = samplerMatrix;
235        }
236
237        fCurrentProgram->fTextureOrientation[s] = texture->orientation();
238    }
239}
240
241
242void GrGpuGL::flushColorMatrix() {
243    UniformHandle matrixUni = fCurrentProgram->fUniforms.fColorMatrixUni;
244    UniformHandle vecUni = fCurrentProgram->fUniforms.fColorMatrixVecUni;
245    if (kInvalidUniformHandle != matrixUni && kInvalidUniformHandle != vecUni) {
246        const float* m = this->getDrawState().getColorMatrix();
247        GrGLfloat mt[]  = {
248            m[0], m[5], m[10], m[15],
249            m[1], m[6], m[11], m[16],
250            m[2], m[7], m[12], m[17],
251            m[3], m[8], m[13], m[18],
252        };
253        static float scale = 1.0f / 255.0f;
254        GrGLfloat vec[] = {
255            m[4] * scale, m[9] * scale, m[14] * scale, m[19] * scale,
256        };
257        fCurrentProgram->fUniformManager.setMatrix4f(matrixUni, mt);
258        fCurrentProgram->fUniformManager.set4fv(vecUni, 0, 1, vec);
259    }
260}
261
262static const float ONE_OVER_255 = 1.f / 255.f;
263
264#define GR_COLOR_TO_VEC4(color) {\
265    GrColorUnpackR(color) * ONE_OVER_255,\
266    GrColorUnpackG(color) * ONE_OVER_255,\
267    GrColorUnpackB(color) * ONE_OVER_255,\
268    GrColorUnpackA(color) * ONE_OVER_255 \
269}
270
271void GrGpuGL::flushColor(GrColor color) {
272    const ProgramDesc& desc = fCurrentProgram->getDesc();
273    const GrDrawState& drawState = this->getDrawState();
274
275    if (this->getVertexLayout() & kColor_VertexLayoutBit) {
276        // color will be specified per-vertex as an attribute
277        // invalidate the const vertex attrib color
278        fHWConstAttribColor = GrColor_ILLEGAL;
279    } else {
280        switch (desc.fColorInput) {
281            case ProgramDesc::kAttribute_ColorInput:
282                if (fHWConstAttribColor != color) {
283                    // OpenGL ES only supports the float varieties of
284                    // glVertexAttrib
285                    float c[] = GR_COLOR_TO_VEC4(color);
286                    GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(),
287                                            c));
288                    fHWConstAttribColor = color;
289                }
290                break;
291            case ProgramDesc::kUniform_ColorInput:
292                if (fCurrentProgram->fColor != color) {
293                    // OpenGL ES doesn't support unsigned byte varieties of
294                    // glUniform
295                    float c[] = GR_COLOR_TO_VEC4(color);
296                    GrAssert(kInvalidUniformHandle !=  fCurrentProgram->fUniforms.fColorUni);
297                    fCurrentProgram->fUniformManager.set4fv(fCurrentProgram->fUniforms.fColorUni,
298                                                            0, 1, c);
299                    fCurrentProgram->fColor = color;
300                }
301                break;
302            case ProgramDesc::kSolidWhite_ColorInput:
303            case ProgramDesc::kTransBlack_ColorInput:
304                break;
305            default:
306                GrCrash("Unknown color type.");
307        }
308    }
309    UniformHandle filterColorUni = fCurrentProgram->fUniforms.fColorFilterUni;
310    if (kInvalidUniformHandle != filterColorUni &&
311        fCurrentProgram->fColorFilterColor != drawState.getColorFilterColor()) {
312        float c[] = GR_COLOR_TO_VEC4(drawState.getColorFilterColor());
313        fCurrentProgram->fUniformManager.set4fv(filterColorUni, 0, 1, c);
314        fCurrentProgram->fColorFilterColor = drawState.getColorFilterColor();
315    }
316}
317
318void GrGpuGL::flushCoverage(GrColor coverage) {
319    const ProgramDesc& desc = fCurrentProgram->getDesc();
320    // const GrDrawState& drawState = this->getDrawState();
321
322
323    if (this->getVertexLayout() & kCoverage_VertexLayoutBit) {
324        // coverage will be specified per-vertex as an attribute
325        // invalidate the const vertex attrib coverage
326        fHWConstAttribCoverage = GrColor_ILLEGAL;
327    } else {
328        switch (desc.fCoverageInput) {
329            case ProgramDesc::kAttribute_ColorInput:
330                if (fHWConstAttribCoverage != coverage) {
331                    // OpenGL ES only supports the float varieties of
332                    // glVertexAttrib
333                    float c[] = GR_COLOR_TO_VEC4(coverage);
334                    GL_CALL(VertexAttrib4fv(GrGLProgram::CoverageAttributeIdx(),
335                                            c));
336                    fHWConstAttribCoverage = coverage;
337                }
338                break;
339            case ProgramDesc::kUniform_ColorInput:
340                if (fCurrentProgram->fCoverage != coverage) {
341                    // OpenGL ES doesn't support unsigned byte varieties of
342                    // glUniform
343                    float c[] = GR_COLOR_TO_VEC4(coverage);
344                    GrAssert(kInvalidUniformHandle !=  fCurrentProgram->fUniforms.fCoverageUni);
345                    fCurrentProgram->fUniformManager.set4fv(fCurrentProgram->fUniforms.fCoverageUni,
346                                                            0, 1, c);
347                    fCurrentProgram->fCoverage = coverage;
348                }
349                break;
350            case ProgramDesc::kSolidWhite_ColorInput:
351            case ProgramDesc::kTransBlack_ColorInput:
352                break;
353            default:
354                GrCrash("Unknown coverage type.");
355        }
356    }
357}
358
359bool GrGpuGL::flushGraphicsState(DrawType type) {
360    const GrDrawState& drawState = this->getDrawState();
361
362    // GrGpu::setupClipAndFlushState should have already checked this
363    // and bailed if not true.
364    GrAssert(NULL != drawState.getRenderTarget());
365
366    if (kStencilPath_DrawType != type) {
367        this->flushMiscFixedFunctionState();
368
369        GrBlendCoeff srcCoeff;
370        GrBlendCoeff dstCoeff;
371        BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
372        if (kSkipDraw_BlendOptFlag & blendOpts) {
373            return false;
374        }
375
376        const GrCustomStage* customStages [GrDrawState::kNumStages];
377        GrGLProgram::Desc desc;
378        this->buildProgram(kDrawPoints_DrawType == type, blendOpts, dstCoeff, customStages, &desc);
379
380        fCurrentProgram.reset(fProgramCache->getProgram(desc, customStages));
381        if (NULL == fCurrentProgram.get()) {
382            GrAssert(!"Failed to create program!");
383            return false;
384        }
385        fCurrentProgram.get()->ref();
386
387        if (fHWProgramID != fCurrentProgram->fProgramID) {
388            GL_CALL(UseProgram(fCurrentProgram->fProgramID));
389            fHWProgramID = fCurrentProgram->fProgramID;
390        }
391        fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff);
392        this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff);
393
394        GrColor color;
395        GrColor coverage;
396        if (blendOpts & kEmitTransBlack_BlendOptFlag) {
397            color = 0;
398            coverage = 0;
399        } else if (blendOpts & kEmitCoverage_BlendOptFlag) {
400            color = 0xffffffff;
401            coverage = drawState.getCoverage();
402        } else {
403            color = drawState.getColor();
404            coverage = drawState.getCoverage();
405        }
406        this->flushColor(color);
407        this->flushCoverage(coverage);
408
409        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
410            if (this->isStageEnabled(s)) {
411                this->flushBoundTextureAndParams(s);
412
413                this->flushTextureMatrix(s);
414
415                if (NULL != fCurrentProgram->fProgramStage[s]) {
416                    const GrSamplerState& sampler = this->getDrawState().getSampler(s);
417                    fCurrentProgram->fProgramStage[s]->setData(fCurrentProgram->fUniformManager,
418                                                               *sampler.getCustomStage(),
419                                                               drawState.getRenderTarget(), s);
420                }
421            }
422        }
423        this->flushColorMatrix();
424    }
425    this->flushStencil(type);
426    this->flushViewMatrix(type);
427    this->flushScissor();
428    this->flushAAState(type);
429
430    GrIRect* devRect = NULL;
431    GrIRect devClipBounds;
432    if (drawState.isClipState()) {
433        fClip->getConservativeBounds(drawState.getRenderTarget(),
434                                     &devClipBounds);
435        devRect = &devClipBounds;
436    }
437    // This must come after textures are flushed because a texture may need
438    // to be msaa-resolved (which will modify bound FBO state).
439    this->flushRenderTarget(devRect);
440
441    return true;
442}
443
444#if GR_TEXT_SCALAR_IS_USHORT
445    #define TEXT_COORDS_GL_TYPE          GR_GL_UNSIGNED_SHORT
446    #define TEXT_COORDS_ARE_NORMALIZED   1
447#elif GR_TEXT_SCALAR_IS_FLOAT
448    #define TEXT_COORDS_GL_TYPE          GR_GL_FLOAT
449    #define TEXT_COORDS_ARE_NORMALIZED   0
450#elif GR_TEXT_SCALAR_IS_FIXED
451    #define TEXT_COORDS_GL_TYPE          GR_GL_FIXED
452    #define TEXT_COORDS_ARE_NORMALIZED   0
453#else
454    #error "unknown GR_TEXT_SCALAR type"
455#endif
456
457void GrGpuGL::setupGeometry(int* startVertex,
458                            int* startIndex,
459                            int vertexCount,
460                            int indexCount) {
461
462    int newColorOffset;
463    int newCoverageOffset;
464    int newTexCoordOffsets[GrDrawState::kMaxTexCoords];
465    int newEdgeOffset;
466
467    GrVertexLayout currLayout = this->getVertexLayout();
468
469    GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
470                                            currLayout,
471                                            newTexCoordOffsets,
472                                            &newColorOffset,
473                                            &newCoverageOffset,
474                                            &newEdgeOffset);
475    int oldColorOffset;
476    int oldCoverageOffset;
477    int oldTexCoordOffsets[GrDrawState::kMaxTexCoords];
478    int oldEdgeOffset;
479
480    GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
481                                            fHWGeometryState.fVertexLayout,
482                                            oldTexCoordOffsets,
483                                            &oldColorOffset,
484                                            &oldCoverageOffset,
485                                            &oldEdgeOffset);
486    bool indexed = NULL != startIndex;
487
488    int extraVertexOffset;
489    int extraIndexOffset;
490    this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
491
492    GrGLenum scalarType;
493    bool texCoordNorm;
494    if (currLayout & kTextFormat_VertexLayoutBit) {
495        scalarType = TEXT_COORDS_GL_TYPE;
496        texCoordNorm = SkToBool(TEXT_COORDS_ARE_NORMALIZED);
497    } else {
498        GR_STATIC_ASSERT(GR_SCALAR_IS_FLOAT);
499        scalarType = GR_GL_FLOAT;
500        texCoordNorm = false;
501    }
502
503    size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
504    *startVertex = 0;
505    if (indexed) {
506        *startIndex += extraIndexOffset;
507    }
508
509    // all the Pointers must be set if any of these are true
510    bool allOffsetsChange =  fHWGeometryState.fArrayPtrsDirty ||
511                             vertexOffset != fHWGeometryState.fVertexOffset ||
512                             newStride != oldStride;
513
514    // position and tex coord offsets change if above conditions are true
515    // or the type/normalization changed based on text vs nontext type coords.
516    bool posAndTexChange = allOffsetsChange ||
517                           (((TEXT_COORDS_GL_TYPE != GR_GL_FLOAT) || TEXT_COORDS_ARE_NORMALIZED) &&
518                                (kTextFormat_VertexLayoutBit &
519                                  (fHWGeometryState.fVertexLayout ^ currLayout)));
520
521    if (posAndTexChange) {
522        int idx = GrGLProgram::PositionAttributeIdx();
523        GL_CALL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
524                                  (GrGLvoid*)vertexOffset));
525        fHWGeometryState.fVertexOffset = vertexOffset;
526    }
527
528    for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
529        if (newTexCoordOffsets[t] > 0) {
530            GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
531            int idx = GrGLProgram::TexCoordAttributeIdx(t);
532            if (oldTexCoordOffsets[t] <= 0) {
533                GL_CALL(EnableVertexAttribArray(idx));
534                GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
535                                          newStride, texCoordOffset));
536            } else if (posAndTexChange ||
537                       newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
538                GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
539                                          newStride, texCoordOffset));
540            }
541        } else if (oldTexCoordOffsets[t] > 0) {
542            GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
543        }
544    }
545
546    if (newColorOffset > 0) {
547        GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
548        int idx = GrGLProgram::ColorAttributeIdx();
549        if (oldColorOffset <= 0) {
550            GL_CALL(EnableVertexAttribArray(idx));
551            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
552                                      true, newStride, colorOffset));
553        } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
554            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
555                                      true, newStride, colorOffset));
556        }
557    } else if (oldColorOffset > 0) {
558        GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
559    }
560
561    if (newCoverageOffset > 0) {
562        GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset);
563        int idx = GrGLProgram::CoverageAttributeIdx();
564        if (oldCoverageOffset <= 0) {
565            GL_CALL(EnableVertexAttribArray(idx));
566            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
567                                        true, newStride, coverageOffset));
568        } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) {
569            GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
570                                        true, newStride, coverageOffset));
571        }
572    } else if (oldCoverageOffset > 0) {
573        GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx()));
574    }
575
576    if (newEdgeOffset > 0) {
577        GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset);
578        int idx = GrGLProgram::EdgeAttributeIdx();
579        if (oldEdgeOffset <= 0) {
580            GL_CALL(EnableVertexAttribArray(idx));
581            GL_CALL(VertexAttribPointer(idx, 4, scalarType,
582                                        false, newStride, edgeOffset));
583        } else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) {
584            GL_CALL(VertexAttribPointer(idx, 4, scalarType,
585                                        false, newStride, edgeOffset));
586        }
587    } else if (oldEdgeOffset > 0) {
588        GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx()));
589    }
590
591    fHWGeometryState.fVertexLayout = currLayout;
592    fHWGeometryState.fArrayPtrsDirty = false;
593}
594
595namespace {
596
597void setup_custom_stage(GrGLProgram::Desc::StageDesc* stage,
598                        const GrSamplerState& sampler,
599                        const GrGLCaps& caps,
600                        const GrCustomStage** customStages,
601                        GrGLProgram* program, int index) {
602    const GrCustomStage* customStage = sampler.getCustomStage();
603    if (customStage) {
604        const GrProgramStageFactory& factory = customStage->getFactory();
605        stage->fCustomStageKey = factory.glStageKey(*customStage, caps);
606        customStages[index] = customStage;
607    } else {
608        stage->fCustomStageKey = 0;
609        customStages[index] = NULL;
610    }
611}
612
613}
614
615void GrGpuGL::buildProgram(bool isPoints,
616                           BlendOptFlags blendOpts,
617                           GrBlendCoeff dstCoeff,
618                           const GrCustomStage** customStages,
619                           ProgramDesc* desc) {
620    const GrDrawState& drawState = this->getDrawState();
621
622    // This should already have been caught
623    GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts));
624
625    bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
626
627    bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag |
628                                           kEmitCoverage_BlendOptFlag));
629
630    // The descriptor is used as a cache key. Thus when a field of the
631    // descriptor will not affect program generation (because of the vertex
632    // layout in use or other descriptor field settings) it should be set
633    // to a canonical value to avoid duplicate programs with different keys.
634
635    // Must initialize all fields or cache will have false negatives!
636    desc->fVertexLayout = this->getVertexLayout();
637
638    desc->fEmitsPointSize = isPoints;
639
640    bool requiresAttributeColors = !skipColor &&
641                                   SkToBool(desc->fVertexLayout & kColor_VertexLayoutBit);
642    bool requiresAttributeCoverage = !skipCoverage &&
643                                     SkToBool(desc->fVertexLayout & kCoverage_VertexLayoutBit);
644
645    // fColorInput/fCoverageInput records how colors are specified for the.
646    // program. So we strip the bits from the layout to avoid false negatives
647    // when searching for an existing program in the cache.
648    desc->fVertexLayout &= ~(kColor_VertexLayoutBit | kCoverage_VertexLayoutBit);
649
650    desc->fColorFilterXfermode = skipColor ?
651                                SkXfermode::kDst_Mode :
652                                drawState.getColorFilterMode();
653
654    desc->fColorMatrixEnabled = drawState.isStateFlagEnabled(GrDrawState::kColorMatrix_StateBit);
655
656    // no reason to do edge aa or look at per-vertex coverage if coverage is
657    // ignored
658    if (skipCoverage) {
659        desc->fVertexLayout &= ~(kEdge_VertexLayoutBit | kCoverage_VertexLayoutBit);
660    }
661
662    bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
663    bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) ||
664                             (!requiresAttributeColors && 0xffffffff == drawState.getColor());
665    if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) {
666        desc->fColorInput = ProgramDesc::kTransBlack_ColorInput;
667    } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) {
668        desc->fColorInput = ProgramDesc::kSolidWhite_ColorInput;
669    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
670        desc->fColorInput = ProgramDesc::kUniform_ColorInput;
671    } else {
672        desc->fColorInput = ProgramDesc::kAttribute_ColorInput;
673    }
674
675    bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage();
676
677    if (skipCoverage) {
678        desc->fCoverageInput = ProgramDesc::kTransBlack_ColorInput;
679    } else if (covIsSolidWhite) {
680        desc->fCoverageInput = ProgramDesc::kSolidWhite_ColorInput;
681    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) {
682        desc->fCoverageInput = ProgramDesc::kUniform_ColorInput;
683    } else {
684        desc->fCoverageInput = ProgramDesc::kAttribute_ColorInput;
685    }
686
687    int lastEnabledStage = -1;
688
689    if (!skipCoverage && (desc->fVertexLayout &GrDrawTarget::kEdge_VertexLayoutBit)) {
690        desc->fVertexEdgeType = drawState.getVertexEdgeType();
691    } else {
692        // use canonical value when not set to avoid cache misses
693        desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
694    }
695
696    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
697        StageDesc& stage = desc->fStages[s];
698
699        stage.fOptFlags = 0;
700        stage.setEnabled(this->isStageEnabled(s));
701
702        bool skip = s < drawState.getFirstCoverageStage() ? skipColor :
703                                                            skipCoverage;
704
705        if (!skip && stage.isEnabled()) {
706            lastEnabledStage = s;
707            const GrSamplerState& sampler = drawState.getSampler(s);
708            // FIXME: Still assuming one texture per custom stage
709            const GrCustomStage* customStage = drawState.getSampler(s).getCustomStage();
710            const GrGLTexture* texture = static_cast<const GrGLTexture*>(customStage->texture(0));
711            stage.fInConfigFlags = 0;
712            if (NULL != texture) {
713                // We call this helper function rather then simply checking the client-specified
714                // texture matrix. This is because we may have to concat a y-inversion to account
715                // for texture orientation.
716                if (TextureMatrixIsIdentity(texture, sampler)) {
717                    stage.fOptFlags |= StageDesc::kIdentityMatrix_OptFlagBit;
718                } else if (!sampler.getMatrix().hasPerspective()) {
719                    stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
720                }
721                if (!this->glCaps().textureSwizzleSupport()) {
722                    if (GrPixelConfigIsAlphaOnly(texture->config())) {
723                        // If we don't have texture swizzle support then the shader must smear the
724                        // single channel after reading the texture.
725                        if (this->glCaps().textureRedSupport()) {
726                            // We can use R8 textures so use kSmearRed.
727                            stage.fInConfigFlags |= StageDesc::kSmearRed_InConfigFlag;
728                        } else {
729                            // We can use A8 textures so use kSmearAlpha.
730                            stage.fInConfigFlags |= StageDesc::kSmearAlpha_InConfigFlag;
731                        }
732                    }
733                }
734            }
735
736            setup_custom_stage(&stage, sampler, this->glCaps(), customStages,
737                               fCurrentProgram.get(), s);
738
739        } else {
740            stage.fOptFlags         = 0;
741            stage.fInConfigFlags    = 0;
742            stage.fCustomStageKey   = 0;
743            customStages[s] = NULL;
744        }
745    }
746
747    desc->fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
748
749    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
750    // other than pass through values fromthe VS to the FS anyway).
751#if 0 && GR_GL_EXPERIMENTAL_GS
752    desc->fExperimentalGS = this->getCaps().fGeometryShaderSupport;
753#endif
754
755    // We want to avoid generating programs with different "first cov stage" values when they would
756    // compute the same result. We set field in the desc to kNumStages when either there are no
757    // coverage stages or the distinction between coverage and color is immaterial.
758    int firstCoverageStage = GrDrawState::kNumStages;
759    desc->fFirstCoverageStage = GrDrawState::kNumStages;
760    bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage;
761    if (hasCoverage) {
762        firstCoverageStage = drawState.getFirstCoverageStage();
763    }
764
765    // other coverage inputs
766    if (!hasCoverage) {
767        hasCoverage = requiresAttributeCoverage ||
768                      (desc->fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit);
769    }
770
771    if (hasCoverage) {
772        // color filter is applied between color/coverage computation
773        if (SkXfermode::kDst_Mode != desc->fColorFilterXfermode) {
774            desc->fFirstCoverageStage = firstCoverageStage;
775        }
776
777        if (this->getCaps().fDualSourceBlendingSupport &&
778            !(blendOpts & (kEmitCoverage_BlendOptFlag | kCoverageAsAlpha_BlendOptFlag))) {
779            if (kZero_GrBlendCoeff == dstCoeff) {
780                // write the coverage value to second color
781                desc->fDualSrcOutput =  ProgramDesc::kCoverage_DualSrcOutput;
782                desc->fFirstCoverageStage = firstCoverageStage;
783            } else if (kSA_GrBlendCoeff == dstCoeff) {
784                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
785                desc->fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
786                desc->fFirstCoverageStage = firstCoverageStage;
787            } else if (kSC_GrBlendCoeff == dstCoeff) {
788                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
789                desc->fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
790                desc->fFirstCoverageStage = firstCoverageStage;
791            }
792        }
793    }
794}
795