1/*
2 * Copyright 2013 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 "GrGLVertexArray.h"
9#include "GrGLBuffer.h"
10#include "GrGLGpu.h"
11
12struct AttribLayout {
13    bool        fNormalized;  // Only used by floating point types.
14    uint8_t     fCount;
15    uint16_t    fType;
16};
17
18GR_STATIC_ASSERT(4 == sizeof(AttribLayout));
19
20static AttribLayout attrib_layout(GrVertexAttribType type) {
21    switch (type) {
22        case kFloat_GrVertexAttribType:
23            return {false, 1, GR_GL_FLOAT};
24        case kVec2f_GrVertexAttribType:
25            return {false, 2, GR_GL_FLOAT};
26        case kVec3f_GrVertexAttribType:
27            return {false, 3, GR_GL_FLOAT};
28        case kVec4f_GrVertexAttribType:
29            return {false, 4, GR_GL_FLOAT};
30        case kVec2i_GrVertexAttribType:
31            return {false, 2, GR_GL_INT};
32        case kVec3i_GrVertexAttribType:
33            return {false, 3, GR_GL_INT};
34        case kVec4i_GrVertexAttribType:
35            return {false, 4, GR_GL_INT};
36        case kUByte_GrVertexAttribType:
37            return {true, 1, GR_GL_UNSIGNED_BYTE};
38        case kVec4ub_GrVertexAttribType:
39            return {true, 4, GR_GL_UNSIGNED_BYTE};
40        case kVec2us_GrVertexAttribType:
41            return {true, 2, GR_GL_UNSIGNED_SHORT};
42        case kInt_GrVertexAttribType:
43            return {false, 1, GR_GL_INT};
44        case kUint_GrVertexAttribType:
45            return {false, 1, GR_GL_UNSIGNED_INT};
46    }
47    SkFAIL("Unknown vertex attrib type");
48    return {false, 0, 0};
49};
50
51void GrGLAttribArrayState::set(GrGLGpu* gpu,
52                               int index,
53                               const GrBuffer* vertexBuffer,
54                               GrVertexAttribType type,
55                               GrGLsizei stride,
56                               GrGLvoid* offset) {
57    SkASSERT(index >= 0 && index < fAttribArrayStates.count());
58    AttribArrayState* array = &fAttribArrayStates[index];
59    if (!array->fEnableIsValid || !array->fEnabled) {
60        GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(index));
61        array->fEnableIsValid = true;
62        array->fEnabled = true;
63    }
64    if (array->fVertexBufferUniqueID != vertexBuffer->uniqueID() ||
65        array->fType != type ||
66        array->fStride != stride ||
67        array->fOffset != offset) {
68        gpu->bindBuffer(kVertex_GrBufferType, vertexBuffer);
69        const AttribLayout& layout = attrib_layout(type);
70        if (!GrVertexAttribTypeIsIntType(type)) {
71            GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index,
72                                                               layout.fCount,
73                                                               layout.fType,
74                                                               layout.fNormalized,
75                                                               stride,
76                                                               offset));
77        } else {
78            SkASSERT(gpu->caps()->shaderCaps()->integerSupport());
79            SkASSERT(!layout.fNormalized);
80            GR_GL_CALL(gpu->glInterface(), VertexAttribIPointer(index,
81                                                                layout.fCount,
82                                                                layout.fType,
83                                                                stride,
84                                                                offset));
85        }
86        array->fVertexBufferUniqueID = vertexBuffer->uniqueID();
87        array->fType = type;
88        array->fStride = stride;
89        array->fOffset = offset;
90    }
91}
92
93void GrGLAttribArrayState::disableUnusedArrays(const GrGLGpu* gpu, uint64_t usedMask) {
94    int count = fAttribArrayStates.count();
95    for (int i = 0; i < count; ++i) {
96        if (!(usedMask & 0x1)) {
97            if (!fAttribArrayStates[i].fEnableIsValid || fAttribArrayStates[i].fEnabled) {
98                GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i));
99                fAttribArrayStates[i].fEnableIsValid = true;
100                fAttribArrayStates[i].fEnabled = false;
101            }
102        } else {
103            SkASSERT(fAttribArrayStates[i].fEnableIsValid && fAttribArrayStates[i].fEnabled);
104        }
105        // if the count is greater than 64 then this will become 0 and we will disable arrays 64+.
106        usedMask >>= 1;
107    }
108}
109
110///////////////////////////////////////////////////////////////////////////////////////////////////
111
112GrGLVertexArray::GrGLVertexArray(GrGLint id, int attribCount)
113    : fID(id)
114    , fAttribArrays(attribCount)
115    , fIndexBufferUniqueID(SK_InvalidUniqueID) {
116}
117
118GrGLAttribArrayState* GrGLVertexArray::bind(GrGLGpu* gpu) {
119    if (0 == fID) {
120        return nullptr;
121    }
122    gpu->bindVertexArray(fID);
123    return &fAttribArrays;
124}
125
126GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, const GrBuffer* ibuff) {
127    GrGLAttribArrayState* state = this->bind(gpu);
128    if (state && fIndexBufferUniqueID != ibuff->uniqueID()) {
129        if (ibuff->isCPUBacked()) {
130            GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 0));
131        } else {
132            const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(ibuff);
133            GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER,
134                                                      glBuffer->bufferID()));
135        }
136        fIndexBufferUniqueID = ibuff->uniqueID();
137    }
138    return state;
139}
140
141void GrGLVertexArray::invalidateCachedState() {
142    fAttribArrays.invalidate();
143    fIndexBufferUniqueID.makeInvalid();
144}
145