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 "src/gpu/GrCpuBuffer.h"
9#include "src/gpu/gl/GrGLBuffer.h"
10#include "src/gpu/gl/GrGLGpu.h"
11#include "src/gpu/gl/GrGLVertexArray.h"
12
13struct AttribLayout {
14    bool        fNormalized;  // Only used by floating point types.
15    uint8_t     fCount;
16    uint16_t    fType;
17};
18
19static_assert(4 == sizeof(AttribLayout));
20
21static AttribLayout attrib_layout(GrVertexAttribType type) {
22    switch (type) {
23        case kFloat_GrVertexAttribType:
24            return {false, 1, GR_GL_FLOAT};
25        case kFloat2_GrVertexAttribType:
26            return {false, 2, GR_GL_FLOAT};
27        case kFloat3_GrVertexAttribType:
28            return {false, 3, GR_GL_FLOAT};
29        case kFloat4_GrVertexAttribType:
30            return {false, 4, GR_GL_FLOAT};
31        case kHalf_GrVertexAttribType:
32            return {false, 1, GR_GL_HALF_FLOAT};
33        case kHalf2_GrVertexAttribType:
34            return {false, 2, GR_GL_HALF_FLOAT};
35        case kHalf4_GrVertexAttribType:
36            return {false, 4, GR_GL_HALF_FLOAT};
37        case kInt2_GrVertexAttribType:
38            return {false, 2, GR_GL_INT};
39        case kInt3_GrVertexAttribType:
40            return {false, 3, GR_GL_INT};
41        case kInt4_GrVertexAttribType:
42            return {false, 4, GR_GL_INT};
43        case kByte_GrVertexAttribType:
44            return {false, 1, GR_GL_BYTE};
45        case kByte2_GrVertexAttribType:
46            return {false, 2, GR_GL_BYTE};
47        case kByte4_GrVertexAttribType:
48            return {false, 4, GR_GL_BYTE};
49        case kUByte_GrVertexAttribType:
50            return {false, 1, GR_GL_UNSIGNED_BYTE};
51        case kUByte2_GrVertexAttribType:
52            return {false, 2, GR_GL_UNSIGNED_BYTE};
53        case kUByte4_GrVertexAttribType:
54            return {false, 4, GR_GL_UNSIGNED_BYTE};
55        case kUByte_norm_GrVertexAttribType:
56            return {true, 1, GR_GL_UNSIGNED_BYTE};
57        case kUByte4_norm_GrVertexAttribType:
58            return {true, 4, GR_GL_UNSIGNED_BYTE};
59        case kShort2_GrVertexAttribType:
60            return {false, 2, GR_GL_SHORT};
61        case kShort4_GrVertexAttribType:
62            return {false, 4, GR_GL_SHORT};
63        case kUShort2_GrVertexAttribType:
64            return {false, 2, GR_GL_UNSIGNED_SHORT};
65        case kUShort2_norm_GrVertexAttribType:
66            return {true, 2, GR_GL_UNSIGNED_SHORT};
67        case kInt_GrVertexAttribType:
68            return {false, 1, GR_GL_INT};
69        case kUInt_GrVertexAttribType:
70            return {false, 1, GR_GL_UNSIGNED_INT};
71        case kUShort_norm_GrVertexAttribType:
72            return {true, 1, GR_GL_UNSIGNED_SHORT};
73        case kUShort4_norm_GrVertexAttribType:
74            return {true, 4, GR_GL_UNSIGNED_SHORT};
75    }
76    SK_ABORT("Unknown vertex attrib type");
77};
78
79void GrGLAttribArrayState::set(GrGLGpu* gpu,
80                               int index,
81                               const GrBuffer* vertexBuffer,
82                               GrVertexAttribType cpuType,
83                               GrSLType gpuType,
84                               GrGLsizei stride,
85                               size_t offsetInBytes,
86                               int divisor) {
87    SkASSERT(index >= 0 && index < fAttribArrayStates.count());
88    SkASSERT(0 == divisor || gpu->caps()->drawInstancedSupport());
89    AttribArrayState* array = &fAttribArrayStates[index];
90    const char* offsetAsPtr;
91    bool bufferChanged = false;
92    if (vertexBuffer->isCpuBuffer()) {
93        if (!array->fUsingCpuBuffer) {
94            bufferChanged = true;
95            array->fUsingCpuBuffer = true;
96        }
97        offsetAsPtr = static_cast<const GrCpuBuffer*>(vertexBuffer)->data() + offsetInBytes;
98    } else {
99        auto gpuBuffer = static_cast<const GrGpuBuffer*>(vertexBuffer);
100        if (array->fUsingCpuBuffer || array->fVertexBufferUniqueID != gpuBuffer->uniqueID()) {
101            bufferChanged = true;
102            array->fVertexBufferUniqueID = gpuBuffer->uniqueID();
103        }
104        offsetAsPtr = reinterpret_cast<const char*>(offsetInBytes);
105    }
106    if (bufferChanged ||
107        array->fCPUType != cpuType ||
108        array->fGPUType != gpuType ||
109        array->fStride != stride ||
110        array->fOffset != offsetAsPtr) {
111        // We always have to call this if we're going to change the array pointer. 'array' is
112        // tracking the last buffer used to setup attrib pointers, not the last buffer bound.
113        // GrGLGpu will avoid redundant binds.
114        gpu->bindBuffer(GrGpuBufferType::kVertex, vertexBuffer);
115        const AttribLayout& layout = attrib_layout(cpuType);
116        if (GrSLTypeIsFloatType(gpuType)) {
117            GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index,
118                                                               layout.fCount,
119                                                               layout.fType,
120                                                               layout.fNormalized,
121                                                               stride,
122                                                               offsetAsPtr));
123        } else {
124            SkASSERT(gpu->caps()->shaderCaps()->integerSupport());
125            SkASSERT(!layout.fNormalized);
126            GR_GL_CALL(gpu->glInterface(), VertexAttribIPointer(index,
127                                                                layout.fCount,
128                                                                layout.fType,
129                                                                stride,
130                                                                offsetAsPtr));
131        }
132        array->fCPUType = cpuType;
133        array->fGPUType = gpuType;
134        array->fStride = stride;
135        array->fOffset = offsetAsPtr;
136    }
137    if (gpu->caps()->drawInstancedSupport() && array->fDivisor != divisor) {
138        SkASSERT(0 == divisor || 1 == divisor); // not necessarily a requirement but what we expect.
139        GR_GL_CALL(gpu->glInterface(), VertexAttribDivisor(index, divisor));
140        array->fDivisor = divisor;
141    }
142}
143
144void GrGLAttribArrayState::enableVertexArrays(const GrGLGpu* gpu, int enabledCount,
145                                              GrPrimitiveRestart enablePrimitiveRestart) {
146    SkASSERT(enabledCount <= fAttribArrayStates.count());
147
148    if (!fEnableStateIsValid || enabledCount != fNumEnabledArrays) {
149        int firstIdxToEnable = fEnableStateIsValid ? fNumEnabledArrays : 0;
150        for (int i = firstIdxToEnable; i < enabledCount; ++i) {
151            GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(i));
152        }
153
154        int endIdxToDisable = fEnableStateIsValid ? fNumEnabledArrays : fAttribArrayStates.count();
155        for (int i = enabledCount; i < endIdxToDisable; ++i) {
156            GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i));
157        }
158
159        fNumEnabledArrays = enabledCount;
160    }
161
162    SkASSERT(GrPrimitiveRestart::kNo == enablePrimitiveRestart ||
163             gpu->caps()->usePrimitiveRestart());
164
165    if (gpu->caps()->usePrimitiveRestart() &&
166        (!fEnableStateIsValid || enablePrimitiveRestart != fPrimitiveRestartEnabled)) {
167        if (GrPrimitiveRestart::kYes == enablePrimitiveRestart) {
168            GR_GL_CALL(gpu->glInterface(), Enable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX));
169        } else {
170            GR_GL_CALL(gpu->glInterface(), Disable(GR_GL_PRIMITIVE_RESTART_FIXED_INDEX));
171        }
172
173        fPrimitiveRestartEnabled = enablePrimitiveRestart;
174    }
175
176    fEnableStateIsValid = true;
177}
178
179///////////////////////////////////////////////////////////////////////////////////////////////////
180
181GrGLVertexArray::GrGLVertexArray(GrGLint id, int attribCount)
182    : fID(id)
183    , fAttribArrays(attribCount)
184    , fIndexBufferUniqueID(SK_InvalidUniqueID) {
185}
186
187GrGLAttribArrayState* GrGLVertexArray::bind(GrGLGpu* gpu) {
188    if (0 == fID) {
189        return nullptr;
190    }
191    gpu->bindVertexArray(fID);
192    return &fAttribArrays;
193}
194
195GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, const GrBuffer* ibuff) {
196    GrGLAttribArrayState* state = this->bind(gpu);
197    if (!state) {
198        return nullptr;
199    }
200    if (ibuff->isCpuBuffer()) {
201        GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, 0));
202    } else {
203        const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(ibuff);
204        if (fIndexBufferUniqueID != glBuffer->uniqueID()) {
205            GR_GL_CALL(gpu->glInterface(),
206                       BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, glBuffer->bufferID()));
207            fIndexBufferUniqueID = glBuffer->uniqueID();
208        }
209    }
210    return state;
211}
212
213void GrGLVertexArray::invalidateCachedState() {
214    fAttribArrays.invalidate();
215    fIndexBufferUniqueID.makeInvalid();
216}
217