xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker 
7*8975f5c5SAndroid Build Coastguard Worker // VertexDataManager.h: Defines the VertexDataManager, a class that
8*8975f5c5SAndroid Build Coastguard Worker // runs the Buffer translation process.
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/d3d/VertexDataManager.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include "common/bitset_utils.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Buffer.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Program.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/State.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/VertexArray.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/VertexAttribute.h"
19*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/formatutils.h"
20*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/d3d/BufferD3D.h"
21*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/d3d/ContextD3D.h"
22*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/d3d/VertexBuffer.h"
23*8975f5c5SAndroid Build Coastguard Worker 
24*8975f5c5SAndroid Build Coastguard Worker using namespace angle;
25*8975f5c5SAndroid Build Coastguard Worker 
26*8975f5c5SAndroid Build Coastguard Worker namespace rx
27*8975f5c5SAndroid Build Coastguard Worker {
28*8975f5c5SAndroid Build Coastguard Worker namespace
29*8975f5c5SAndroid Build Coastguard Worker {
30*8975f5c5SAndroid Build Coastguard Worker enum
31*8975f5c5SAndroid Build Coastguard Worker {
32*8975f5c5SAndroid Build Coastguard Worker     INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024
33*8975f5c5SAndroid Build Coastguard Worker };
34*8975f5c5SAndroid Build Coastguard Worker // This has to be at least 4k or else it fails on ATI cards.
35*8975f5c5SAndroid Build Coastguard Worker enum
36*8975f5c5SAndroid Build Coastguard Worker {
37*8975f5c5SAndroid Build Coastguard Worker     CONSTANT_VERTEX_BUFFER_SIZE = 4096
38*8975f5c5SAndroid Build Coastguard Worker };
39*8975f5c5SAndroid Build Coastguard Worker 
40*8975f5c5SAndroid Build Coastguard Worker // Warning: ensure the binding matches attrib.bindingIndex before using these functions.
GetMaxAttributeByteOffsetForDraw(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,int64_t elementCount)41*8975f5c5SAndroid Build Coastguard Worker int64_t GetMaxAttributeByteOffsetForDraw(const gl::VertexAttribute &attrib,
42*8975f5c5SAndroid Build Coastguard Worker                                          const gl::VertexBinding &binding,
43*8975f5c5SAndroid Build Coastguard Worker                                          int64_t elementCount)
44*8975f5c5SAndroid Build Coastguard Worker {
45*8975f5c5SAndroid Build Coastguard Worker     CheckedNumeric<int64_t> stride = ComputeVertexAttributeStride(attrib, binding);
46*8975f5c5SAndroid Build Coastguard Worker     CheckedNumeric<int64_t> offset = ComputeVertexAttributeOffset(attrib, binding);
47*8975f5c5SAndroid Build Coastguard Worker     CheckedNumeric<int64_t> size   = ComputeVertexAttributeTypeSize(attrib);
48*8975f5c5SAndroid Build Coastguard Worker 
49*8975f5c5SAndroid Build Coastguard Worker     ASSERT(elementCount > 0);
50*8975f5c5SAndroid Build Coastguard Worker 
51*8975f5c5SAndroid Build Coastguard Worker     CheckedNumeric<int64_t> result =
52*8975f5c5SAndroid Build Coastguard Worker         stride * (CheckedNumeric<int64_t>(elementCount) - 1) + size + offset;
53*8975f5c5SAndroid Build Coastguard Worker     return result.ValueOrDefault(std::numeric_limits<int64_t>::max());
54*8975f5c5SAndroid Build Coastguard Worker }
55*8975f5c5SAndroid Build Coastguard Worker 
56*8975f5c5SAndroid Build Coastguard Worker // Warning: ensure the binding matches attrib.bindingIndex before using these functions.
ElementsInBuffer(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,unsigned int size)57*8975f5c5SAndroid Build Coastguard Worker int ElementsInBuffer(const gl::VertexAttribute &attrib,
58*8975f5c5SAndroid Build Coastguard Worker                      const gl::VertexBinding &binding,
59*8975f5c5SAndroid Build Coastguard Worker                      unsigned int size)
60*8975f5c5SAndroid Build Coastguard Worker {
61*8975f5c5SAndroid Build Coastguard Worker     angle::CheckedNumeric<int64_t> bufferSize(size);
62*8975f5c5SAndroid Build Coastguard Worker     angle::CheckedNumeric<int64_t> stride      = ComputeVertexAttributeStride(attrib, binding);
63*8975f5c5SAndroid Build Coastguard Worker     angle::CheckedNumeric<int64_t> offset      = ComputeVertexAttributeOffset(attrib, binding);
64*8975f5c5SAndroid Build Coastguard Worker     angle::CheckedNumeric<int64_t> elementSize = ComputeVertexAttributeTypeSize(attrib);
65*8975f5c5SAndroid Build Coastguard Worker 
66*8975f5c5SAndroid Build Coastguard Worker     auto elementsInBuffer    = (bufferSize - (offset % stride) + (stride - elementSize)) / stride;
67*8975f5c5SAndroid Build Coastguard Worker     auto elementsInBufferInt = elementsInBuffer.Cast<int>();
68*8975f5c5SAndroid Build Coastguard Worker 
69*8975f5c5SAndroid Build Coastguard Worker     return elementsInBufferInt.ValueOrDefault(0);
70*8975f5c5SAndroid Build Coastguard Worker }
71*8975f5c5SAndroid Build Coastguard Worker 
72*8975f5c5SAndroid Build Coastguard Worker // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
DirectStoragePossible(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)73*8975f5c5SAndroid Build Coastguard Worker bool DirectStoragePossible(const gl::Context *context,
74*8975f5c5SAndroid Build Coastguard Worker                            const gl::VertexAttribute &attrib,
75*8975f5c5SAndroid Build Coastguard Worker                            const gl::VertexBinding &binding)
76*8975f5c5SAndroid Build Coastguard Worker {
77*8975f5c5SAndroid Build Coastguard Worker     // Current value attribs may not use direct storage.
78*8975f5c5SAndroid Build Coastguard Worker     if (!attrib.enabled)
79*8975f5c5SAndroid Build Coastguard Worker     {
80*8975f5c5SAndroid Build Coastguard Worker         return false;
81*8975f5c5SAndroid Build Coastguard Worker     }
82*8975f5c5SAndroid Build Coastguard Worker 
83*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer = binding.getBuffer().get();
84*8975f5c5SAndroid Build Coastguard Worker     if (!buffer)
85*8975f5c5SAndroid Build Coastguard Worker     {
86*8975f5c5SAndroid Build Coastguard Worker         return false;
87*8975f5c5SAndroid Build Coastguard Worker     }
88*8975f5c5SAndroid Build Coastguard Worker 
89*8975f5c5SAndroid Build Coastguard Worker     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
90*8975f5c5SAndroid Build Coastguard Worker     ASSERT(bufferD3D);
91*8975f5c5SAndroid Build Coastguard Worker     if (!bufferD3D->supportsDirectBinding())
92*8975f5c5SAndroid Build Coastguard Worker     {
93*8975f5c5SAndroid Build Coastguard Worker         return false;
94*8975f5c5SAndroid Build Coastguard Worker     }
95*8975f5c5SAndroid Build Coastguard Worker 
96*8975f5c5SAndroid Build Coastguard Worker     // Alignment restrictions: In D3D, vertex data must be aligned to the format stride, or to a
97*8975f5c5SAndroid Build Coastguard Worker     // 4-byte boundary, whichever is smaller. (Undocumented, and experimentally confirmed)
98*8975f5c5SAndroid Build Coastguard Worker     size_t alignment = 4;
99*8975f5c5SAndroid Build Coastguard Worker 
100*8975f5c5SAndroid Build Coastguard Worker     // TODO(jmadill): add VertexFormatCaps
101*8975f5c5SAndroid Build Coastguard Worker     BufferFactoryD3D *factory = bufferD3D->getFactory();
102*8975f5c5SAndroid Build Coastguard Worker 
103*8975f5c5SAndroid Build Coastguard Worker     angle::FormatID vertexFormatID = attrib.format->id;
104*8975f5c5SAndroid Build Coastguard Worker 
105*8975f5c5SAndroid Build Coastguard Worker     // CPU-converted vertex data must be converted (naturally).
106*8975f5c5SAndroid Build Coastguard Worker     if ((factory->getVertexConversionType(vertexFormatID) & VERTEX_CONVERT_CPU) != 0)
107*8975f5c5SAndroid Build Coastguard Worker     {
108*8975f5c5SAndroid Build Coastguard Worker         return false;
109*8975f5c5SAndroid Build Coastguard Worker     }
110*8975f5c5SAndroid Build Coastguard Worker 
111*8975f5c5SAndroid Build Coastguard Worker     if (attrib.format->vertexAttribType != gl::VertexAttribType::Float)
112*8975f5c5SAndroid Build Coastguard Worker     {
113*8975f5c5SAndroid Build Coastguard Worker         unsigned int elementSize = 0;
114*8975f5c5SAndroid Build Coastguard Worker         angle::Result error =
115*8975f5c5SAndroid Build Coastguard Worker             factory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &elementSize);
116*8975f5c5SAndroid Build Coastguard Worker         ASSERT(error == angle::Result::Continue);
117*8975f5c5SAndroid Build Coastguard Worker         alignment = std::min<size_t>(elementSize, 4);
118*8975f5c5SAndroid Build Coastguard Worker     }
119*8975f5c5SAndroid Build Coastguard Worker 
120*8975f5c5SAndroid Build Coastguard Worker     GLintptr offset = ComputeVertexAttributeOffset(attrib, binding);
121*8975f5c5SAndroid Build Coastguard Worker     // Final alignment check - unaligned data must be converted.
122*8975f5c5SAndroid Build Coastguard Worker     return (static_cast<size_t>(ComputeVertexAttributeStride(attrib, binding)) % alignment == 0) &&
123*8975f5c5SAndroid Build Coastguard Worker            (static_cast<size_t>(offset) % alignment == 0);
124*8975f5c5SAndroid Build Coastguard Worker }
125*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
126*8975f5c5SAndroid Build Coastguard Worker 
TranslatedAttribute()127*8975f5c5SAndroid Build Coastguard Worker TranslatedAttribute::TranslatedAttribute()
128*8975f5c5SAndroid Build Coastguard Worker     : active(false),
129*8975f5c5SAndroid Build Coastguard Worker       attribute(nullptr),
130*8975f5c5SAndroid Build Coastguard Worker       binding(nullptr),
131*8975f5c5SAndroid Build Coastguard Worker       currentValueType(gl::VertexAttribType::InvalidEnum),
132*8975f5c5SAndroid Build Coastguard Worker       baseOffset(0),
133*8975f5c5SAndroid Build Coastguard Worker       usesFirstVertexOffset(false),
134*8975f5c5SAndroid Build Coastguard Worker       stride(0),
135*8975f5c5SAndroid Build Coastguard Worker       vertexBuffer(),
136*8975f5c5SAndroid Build Coastguard Worker       storage(nullptr),
137*8975f5c5SAndroid Build Coastguard Worker       serial(0),
138*8975f5c5SAndroid Build Coastguard Worker       divisor(0)
139*8975f5c5SAndroid Build Coastguard Worker {}
140*8975f5c5SAndroid Build Coastguard Worker 
141*8975f5c5SAndroid Build Coastguard Worker TranslatedAttribute::TranslatedAttribute(const TranslatedAttribute &other) = default;
142*8975f5c5SAndroid Build Coastguard Worker 
computeOffset(const gl::Context * context,GLint startVertex,unsigned int * offsetOut) const143*8975f5c5SAndroid Build Coastguard Worker angle::Result TranslatedAttribute::computeOffset(const gl::Context *context,
144*8975f5c5SAndroid Build Coastguard Worker                                                  GLint startVertex,
145*8975f5c5SAndroid Build Coastguard Worker                                                  unsigned int *offsetOut) const
146*8975f5c5SAndroid Build Coastguard Worker {
147*8975f5c5SAndroid Build Coastguard Worker     if (!usesFirstVertexOffset)
148*8975f5c5SAndroid Build Coastguard Worker     {
149*8975f5c5SAndroid Build Coastguard Worker         *offsetOut = baseOffset;
150*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
151*8975f5c5SAndroid Build Coastguard Worker     }
152*8975f5c5SAndroid Build Coastguard Worker 
153*8975f5c5SAndroid Build Coastguard Worker     CheckedNumeric<unsigned int> offset(baseOffset);
154*8975f5c5SAndroid Build Coastguard Worker     CheckedNumeric<unsigned int> checkedStride(stride);
155*8975f5c5SAndroid Build Coastguard Worker 
156*8975f5c5SAndroid Build Coastguard Worker     offset += checkedStride * static_cast<unsigned int>(startVertex);
157*8975f5c5SAndroid Build Coastguard Worker     ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), offset.IsValid());
158*8975f5c5SAndroid Build Coastguard Worker     *offsetOut = offset.ValueOrDie();
159*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
160*8975f5c5SAndroid Build Coastguard Worker }
161*8975f5c5SAndroid Build Coastguard Worker 
162*8975f5c5SAndroid Build Coastguard Worker // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
ClassifyAttributeStorage(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)163*8975f5c5SAndroid Build Coastguard Worker VertexStorageType ClassifyAttributeStorage(const gl::Context *context,
164*8975f5c5SAndroid Build Coastguard Worker                                            const gl::VertexAttribute &attrib,
165*8975f5c5SAndroid Build Coastguard Worker                                            const gl::VertexBinding &binding)
166*8975f5c5SAndroid Build Coastguard Worker {
167*8975f5c5SAndroid Build Coastguard Worker     // If attribute is disabled, we use the current value.
168*8975f5c5SAndroid Build Coastguard Worker     if (!attrib.enabled)
169*8975f5c5SAndroid Build Coastguard Worker     {
170*8975f5c5SAndroid Build Coastguard Worker         return VertexStorageType::CURRENT_VALUE;
171*8975f5c5SAndroid Build Coastguard Worker     }
172*8975f5c5SAndroid Build Coastguard Worker 
173*8975f5c5SAndroid Build Coastguard Worker     // If specified with immediate data, we must use dynamic storage.
174*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer = binding.getBuffer().get();
175*8975f5c5SAndroid Build Coastguard Worker     if (!buffer)
176*8975f5c5SAndroid Build Coastguard Worker     {
177*8975f5c5SAndroid Build Coastguard Worker         return VertexStorageType::DYNAMIC;
178*8975f5c5SAndroid Build Coastguard Worker     }
179*8975f5c5SAndroid Build Coastguard Worker 
180*8975f5c5SAndroid Build Coastguard Worker     // Check if the buffer supports direct storage.
181*8975f5c5SAndroid Build Coastguard Worker     if (DirectStoragePossible(context, attrib, binding))
182*8975f5c5SAndroid Build Coastguard Worker     {
183*8975f5c5SAndroid Build Coastguard Worker         return VertexStorageType::DIRECT;
184*8975f5c5SAndroid Build Coastguard Worker     }
185*8975f5c5SAndroid Build Coastguard Worker 
186*8975f5c5SAndroid Build Coastguard Worker     // Otherwise the storage is static or dynamic.
187*8975f5c5SAndroid Build Coastguard Worker     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
188*8975f5c5SAndroid Build Coastguard Worker     ASSERT(bufferD3D);
189*8975f5c5SAndroid Build Coastguard Worker     switch (bufferD3D->getUsage())
190*8975f5c5SAndroid Build Coastguard Worker     {
191*8975f5c5SAndroid Build Coastguard Worker         case D3DBufferUsage::DYNAMIC:
192*8975f5c5SAndroid Build Coastguard Worker             return VertexStorageType::DYNAMIC;
193*8975f5c5SAndroid Build Coastguard Worker         case D3DBufferUsage::STATIC:
194*8975f5c5SAndroid Build Coastguard Worker             return VertexStorageType::STATIC;
195*8975f5c5SAndroid Build Coastguard Worker         default:
196*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
197*8975f5c5SAndroid Build Coastguard Worker             return VertexStorageType::UNKNOWN;
198*8975f5c5SAndroid Build Coastguard Worker     }
199*8975f5c5SAndroid Build Coastguard Worker }
200*8975f5c5SAndroid Build Coastguard Worker 
CurrentValueState(BufferFactoryD3D * factory)201*8975f5c5SAndroid Build Coastguard Worker VertexDataManager::CurrentValueState::CurrentValueState(BufferFactoryD3D *factory)
202*8975f5c5SAndroid Build Coastguard Worker     : buffer(new StreamingVertexBufferInterface(factory)), offset(0)
203*8975f5c5SAndroid Build Coastguard Worker {
204*8975f5c5SAndroid Build Coastguard Worker     data.Values.FloatValues[0] = std::numeric_limits<float>::quiet_NaN();
205*8975f5c5SAndroid Build Coastguard Worker     data.Values.FloatValues[1] = std::numeric_limits<float>::quiet_NaN();
206*8975f5c5SAndroid Build Coastguard Worker     data.Values.FloatValues[2] = std::numeric_limits<float>::quiet_NaN();
207*8975f5c5SAndroid Build Coastguard Worker     data.Values.FloatValues[3] = std::numeric_limits<float>::quiet_NaN();
208*8975f5c5SAndroid Build Coastguard Worker     data.Type                  = gl::VertexAttribType::Float;
209*8975f5c5SAndroid Build Coastguard Worker }
210*8975f5c5SAndroid Build Coastguard Worker 
CurrentValueState(CurrentValueState && other)211*8975f5c5SAndroid Build Coastguard Worker VertexDataManager::CurrentValueState::CurrentValueState(CurrentValueState &&other)
212*8975f5c5SAndroid Build Coastguard Worker {
213*8975f5c5SAndroid Build Coastguard Worker     std::swap(buffer, other.buffer);
214*8975f5c5SAndroid Build Coastguard Worker     std::swap(data, other.data);
215*8975f5c5SAndroid Build Coastguard Worker     std::swap(offset, other.offset);
216*8975f5c5SAndroid Build Coastguard Worker }
217*8975f5c5SAndroid Build Coastguard Worker 
~CurrentValueState()218*8975f5c5SAndroid Build Coastguard Worker VertexDataManager::CurrentValueState::~CurrentValueState() {}
219*8975f5c5SAndroid Build Coastguard Worker 
VertexDataManager(BufferFactoryD3D * factory)220*8975f5c5SAndroid Build Coastguard Worker VertexDataManager::VertexDataManager(BufferFactoryD3D *factory)
221*8975f5c5SAndroid Build Coastguard Worker     : mFactory(factory), mStreamingBuffer(factory)
222*8975f5c5SAndroid Build Coastguard Worker {
223*8975f5c5SAndroid Build Coastguard Worker     mCurrentValueCache.reserve(gl::MAX_VERTEX_ATTRIBS);
224*8975f5c5SAndroid Build Coastguard Worker     for (int currentValueIndex = 0; currentValueIndex < gl::MAX_VERTEX_ATTRIBS; ++currentValueIndex)
225*8975f5c5SAndroid Build Coastguard Worker     {
226*8975f5c5SAndroid Build Coastguard Worker         mCurrentValueCache.emplace_back(factory);
227*8975f5c5SAndroid Build Coastguard Worker     }
228*8975f5c5SAndroid Build Coastguard Worker }
229*8975f5c5SAndroid Build Coastguard Worker 
~VertexDataManager()230*8975f5c5SAndroid Build Coastguard Worker VertexDataManager::~VertexDataManager() {}
231*8975f5c5SAndroid Build Coastguard Worker 
initialize(const gl::Context * context)232*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexDataManager::initialize(const gl::Context *context)
233*8975f5c5SAndroid Build Coastguard Worker {
234*8975f5c5SAndroid Build Coastguard Worker     return mStreamingBuffer.initialize(context, INITIAL_STREAM_BUFFER_SIZE);
235*8975f5c5SAndroid Build Coastguard Worker }
236*8975f5c5SAndroid Build Coastguard Worker 
deinitialize()237*8975f5c5SAndroid Build Coastguard Worker void VertexDataManager::deinitialize()
238*8975f5c5SAndroid Build Coastguard Worker {
239*8975f5c5SAndroid Build Coastguard Worker     mStreamingBuffer.reset();
240*8975f5c5SAndroid Build Coastguard Worker     mCurrentValueCache.clear();
241*8975f5c5SAndroid Build Coastguard Worker }
242*8975f5c5SAndroid Build Coastguard Worker 
prepareVertexData(const gl::Context * context,GLint start,GLsizei count,std::vector<TranslatedAttribute> * translatedAttribs,GLsizei instances)243*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexDataManager::prepareVertexData(
244*8975f5c5SAndroid Build Coastguard Worker     const gl::Context *context,
245*8975f5c5SAndroid Build Coastguard Worker     GLint start,
246*8975f5c5SAndroid Build Coastguard Worker     GLsizei count,
247*8975f5c5SAndroid Build Coastguard Worker     std::vector<TranslatedAttribute> *translatedAttribs,
248*8975f5c5SAndroid Build Coastguard Worker     GLsizei instances)
249*8975f5c5SAndroid Build Coastguard Worker {
250*8975f5c5SAndroid Build Coastguard Worker     const gl::State &state                  = context->getState();
251*8975f5c5SAndroid Build Coastguard Worker     const gl::ProgramExecutable *executable = state.getProgramExecutable();
252*8975f5c5SAndroid Build Coastguard Worker     const gl::VertexArray *vertexArray      = state.getVertexArray();
253*8975f5c5SAndroid Build Coastguard Worker     const auto &vertexAttributes            = vertexArray->getVertexAttributes();
254*8975f5c5SAndroid Build Coastguard Worker     const auto &vertexBindings              = vertexArray->getVertexBindings();
255*8975f5c5SAndroid Build Coastguard Worker 
256*8975f5c5SAndroid Build Coastguard Worker     mDynamicAttribsMaskCache.reset();
257*8975f5c5SAndroid Build Coastguard Worker 
258*8975f5c5SAndroid Build Coastguard Worker     translatedAttribs->clear();
259*8975f5c5SAndroid Build Coastguard Worker 
260*8975f5c5SAndroid Build Coastguard Worker     for (size_t attribIndex = 0; attribIndex < vertexAttributes.size(); ++attribIndex)
261*8975f5c5SAndroid Build Coastguard Worker     {
262*8975f5c5SAndroid Build Coastguard Worker         // Skip attrib locations the program doesn't use.
263*8975f5c5SAndroid Build Coastguard Worker         if (!executable->isAttribLocationActive(attribIndex))
264*8975f5c5SAndroid Build Coastguard Worker             continue;
265*8975f5c5SAndroid Build Coastguard Worker 
266*8975f5c5SAndroid Build Coastguard Worker         const auto &attrib  = vertexAttributes[attribIndex];
267*8975f5c5SAndroid Build Coastguard Worker         const auto &binding = vertexBindings[attrib.bindingIndex];
268*8975f5c5SAndroid Build Coastguard Worker 
269*8975f5c5SAndroid Build Coastguard Worker         // Resize automatically puts in empty attribs
270*8975f5c5SAndroid Build Coastguard Worker         translatedAttribs->resize(attribIndex + 1);
271*8975f5c5SAndroid Build Coastguard Worker 
272*8975f5c5SAndroid Build Coastguard Worker         TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex];
273*8975f5c5SAndroid Build Coastguard Worker         auto currentValueData           = state.getVertexAttribCurrentValue(attribIndex);
274*8975f5c5SAndroid Build Coastguard Worker 
275*8975f5c5SAndroid Build Coastguard Worker         // Record the attribute now
276*8975f5c5SAndroid Build Coastguard Worker         translated->active           = true;
277*8975f5c5SAndroid Build Coastguard Worker         translated->attribute        = &attrib;
278*8975f5c5SAndroid Build Coastguard Worker         translated->binding          = &binding;
279*8975f5c5SAndroid Build Coastguard Worker         translated->currentValueType = currentValueData.Type;
280*8975f5c5SAndroid Build Coastguard Worker         translated->divisor          = binding.getDivisor();
281*8975f5c5SAndroid Build Coastguard Worker 
282*8975f5c5SAndroid Build Coastguard Worker         switch (ClassifyAttributeStorage(context, attrib, binding))
283*8975f5c5SAndroid Build Coastguard Worker         {
284*8975f5c5SAndroid Build Coastguard Worker             case VertexStorageType::STATIC:
285*8975f5c5SAndroid Build Coastguard Worker             {
286*8975f5c5SAndroid Build Coastguard Worker                 // Store static attribute.
287*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(StoreStaticAttrib(context, translated));
288*8975f5c5SAndroid Build Coastguard Worker                 break;
289*8975f5c5SAndroid Build Coastguard Worker             }
290*8975f5c5SAndroid Build Coastguard Worker             case VertexStorageType::DYNAMIC:
291*8975f5c5SAndroid Build Coastguard Worker                 // Dynamic attributes must be handled together.
292*8975f5c5SAndroid Build Coastguard Worker                 mDynamicAttribsMaskCache.set(attribIndex);
293*8975f5c5SAndroid Build Coastguard Worker                 break;
294*8975f5c5SAndroid Build Coastguard Worker             case VertexStorageType::DIRECT:
295*8975f5c5SAndroid Build Coastguard Worker                 // Update translated data for direct attributes.
296*8975f5c5SAndroid Build Coastguard Worker                 StoreDirectAttrib(context, translated);
297*8975f5c5SAndroid Build Coastguard Worker                 break;
298*8975f5c5SAndroid Build Coastguard Worker             case VertexStorageType::CURRENT_VALUE:
299*8975f5c5SAndroid Build Coastguard Worker             {
300*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(storeCurrentValue(context, currentValueData, translated, attribIndex));
301*8975f5c5SAndroid Build Coastguard Worker                 break;
302*8975f5c5SAndroid Build Coastguard Worker             }
303*8975f5c5SAndroid Build Coastguard Worker             default:
304*8975f5c5SAndroid Build Coastguard Worker                 UNREACHABLE();
305*8975f5c5SAndroid Build Coastguard Worker                 break;
306*8975f5c5SAndroid Build Coastguard Worker         }
307*8975f5c5SAndroid Build Coastguard Worker     }
308*8975f5c5SAndroid Build Coastguard Worker 
309*8975f5c5SAndroid Build Coastguard Worker     if (mDynamicAttribsMaskCache.none())
310*8975f5c5SAndroid Build Coastguard Worker     {
311*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
312*8975f5c5SAndroid Build Coastguard Worker     }
313*8975f5c5SAndroid Build Coastguard Worker 
314*8975f5c5SAndroid Build Coastguard Worker     // prepareVertexData is only called by Renderer9 which don't support baseInstance
315*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(storeDynamicAttribs(context, translatedAttribs, mDynamicAttribsMaskCache, start,
316*8975f5c5SAndroid Build Coastguard Worker                                   count, instances, 0u));
317*8975f5c5SAndroid Build Coastguard Worker 
318*8975f5c5SAndroid Build Coastguard Worker     PromoteDynamicAttribs(context, *translatedAttribs, mDynamicAttribsMaskCache, count);
319*8975f5c5SAndroid Build Coastguard Worker 
320*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
321*8975f5c5SAndroid Build Coastguard Worker }
322*8975f5c5SAndroid Build Coastguard Worker 
323*8975f5c5SAndroid Build Coastguard Worker // static
StoreDirectAttrib(const gl::Context * context,TranslatedAttribute * directAttrib)324*8975f5c5SAndroid Build Coastguard Worker void VertexDataManager::StoreDirectAttrib(const gl::Context *context,
325*8975f5c5SAndroid Build Coastguard Worker                                           TranslatedAttribute *directAttrib)
326*8975f5c5SAndroid Build Coastguard Worker {
327*8975f5c5SAndroid Build Coastguard Worker     ASSERT(directAttrib->attribute && directAttrib->binding);
328*8975f5c5SAndroid Build Coastguard Worker     const auto &attrib  = *directAttrib->attribute;
329*8975f5c5SAndroid Build Coastguard Worker     const auto &binding = *directAttrib->binding;
330*8975f5c5SAndroid Build Coastguard Worker 
331*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer = binding.getBuffer().get();
332*8975f5c5SAndroid Build Coastguard Worker     ASSERT(buffer);
333*8975f5c5SAndroid Build Coastguard Worker     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
334*8975f5c5SAndroid Build Coastguard Worker 
335*8975f5c5SAndroid Build Coastguard Worker     ASSERT(DirectStoragePossible(context, attrib, binding));
336*8975f5c5SAndroid Build Coastguard Worker     directAttrib->vertexBuffer.set(nullptr);
337*8975f5c5SAndroid Build Coastguard Worker     directAttrib->storage = bufferD3D;
338*8975f5c5SAndroid Build Coastguard Worker     directAttrib->serial  = bufferD3D->getSerial();
339*8975f5c5SAndroid Build Coastguard Worker     directAttrib->stride = static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding));
340*8975f5c5SAndroid Build Coastguard Worker     directAttrib->baseOffset =
341*8975f5c5SAndroid Build Coastguard Worker         static_cast<unsigned int>(ComputeVertexAttributeOffset(attrib, binding));
342*8975f5c5SAndroid Build Coastguard Worker 
343*8975f5c5SAndroid Build Coastguard Worker     // Instanced vertices do not apply the 'start' offset
344*8975f5c5SAndroid Build Coastguard Worker     directAttrib->usesFirstVertexOffset = (binding.getDivisor() == 0);
345*8975f5c5SAndroid Build Coastguard Worker }
346*8975f5c5SAndroid Build Coastguard Worker 
347*8975f5c5SAndroid Build Coastguard Worker // static
StoreStaticAttrib(const gl::Context * context,TranslatedAttribute * translated)348*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexDataManager::StoreStaticAttrib(const gl::Context *context,
349*8975f5c5SAndroid Build Coastguard Worker                                                    TranslatedAttribute *translated)
350*8975f5c5SAndroid Build Coastguard Worker {
351*8975f5c5SAndroid Build Coastguard Worker     ASSERT(translated->attribute && translated->binding);
352*8975f5c5SAndroid Build Coastguard Worker     const auto &attrib  = *translated->attribute;
353*8975f5c5SAndroid Build Coastguard Worker     const auto &binding = *translated->binding;
354*8975f5c5SAndroid Build Coastguard Worker 
355*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer = binding.getBuffer().get();
356*8975f5c5SAndroid Build Coastguard Worker     ASSERT(buffer && attrib.enabled && !DirectStoragePossible(context, attrib, binding));
357*8975f5c5SAndroid Build Coastguard Worker     BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
358*8975f5c5SAndroid Build Coastguard Worker 
359*8975f5c5SAndroid Build Coastguard Worker     // Compute source data pointer
360*8975f5c5SAndroid Build Coastguard Worker     const uint8_t *sourceData = nullptr;
361*8975f5c5SAndroid Build Coastguard Worker     const int offset          = static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
362*8975f5c5SAndroid Build Coastguard Worker 
363*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(bufferD3D->getData(context, &sourceData));
364*8975f5c5SAndroid Build Coastguard Worker 
365*8975f5c5SAndroid Build Coastguard Worker     if (sourceData)
366*8975f5c5SAndroid Build Coastguard Worker     {
367*8975f5c5SAndroid Build Coastguard Worker         sourceData += offset;
368*8975f5c5SAndroid Build Coastguard Worker     }
369*8975f5c5SAndroid Build Coastguard Worker 
370*8975f5c5SAndroid Build Coastguard Worker     unsigned int streamOffset = 0;
371*8975f5c5SAndroid Build Coastguard Worker 
372*8975f5c5SAndroid Build Coastguard Worker     translated->storage = nullptr;
373*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(bufferD3D->getFactory()->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0,
374*8975f5c5SAndroid Build Coastguard Worker                                                               &translated->stride));
375*8975f5c5SAndroid Build Coastguard Worker 
376*8975f5c5SAndroid Build Coastguard Worker     auto *staticBuffer = bufferD3D->getStaticVertexBuffer(attrib, binding);
377*8975f5c5SAndroid Build Coastguard Worker     ASSERT(staticBuffer);
378*8975f5c5SAndroid Build Coastguard Worker 
379*8975f5c5SAndroid Build Coastguard Worker     if (staticBuffer->empty())
380*8975f5c5SAndroid Build Coastguard Worker     {
381*8975f5c5SAndroid Build Coastguard Worker         // Convert the entire buffer
382*8975f5c5SAndroid Build Coastguard Worker         int totalCount =
383*8975f5c5SAndroid Build Coastguard Worker             ElementsInBuffer(attrib, binding, static_cast<unsigned int>(bufferD3D->getSize()));
384*8975f5c5SAndroid Build Coastguard Worker         int startIndex = offset / static_cast<int>(ComputeVertexAttributeStride(attrib, binding));
385*8975f5c5SAndroid Build Coastguard Worker 
386*8975f5c5SAndroid Build Coastguard Worker         if (totalCount > 0)
387*8975f5c5SAndroid Build Coastguard Worker         {
388*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(staticBuffer->storeStaticAttribute(context, attrib, binding, -startIndex,
389*8975f5c5SAndroid Build Coastguard Worker                                                          totalCount, 0, sourceData));
390*8975f5c5SAndroid Build Coastguard Worker         }
391*8975f5c5SAndroid Build Coastguard Worker     }
392*8975f5c5SAndroid Build Coastguard Worker 
393*8975f5c5SAndroid Build Coastguard Worker     unsigned int firstElementOffset =
394*8975f5c5SAndroid Build Coastguard Worker         (static_cast<unsigned int>(offset) /
395*8975f5c5SAndroid Build Coastguard Worker          static_cast<unsigned int>(ComputeVertexAttributeStride(attrib, binding))) *
396*8975f5c5SAndroid Build Coastguard Worker         translated->stride;
397*8975f5c5SAndroid Build Coastguard Worker 
398*8975f5c5SAndroid Build Coastguard Worker     VertexBuffer *vertexBuffer = staticBuffer->getVertexBuffer();
399*8975f5c5SAndroid Build Coastguard Worker 
400*8975f5c5SAndroid Build Coastguard Worker     CheckedNumeric<unsigned int> checkedOffset(streamOffset);
401*8975f5c5SAndroid Build Coastguard Worker     checkedOffset += firstElementOffset;
402*8975f5c5SAndroid Build Coastguard Worker 
403*8975f5c5SAndroid Build Coastguard Worker     ANGLE_CHECK_GL_MATH(GetImplAs<ContextD3D>(context), checkedOffset.IsValid());
404*8975f5c5SAndroid Build Coastguard Worker 
405*8975f5c5SAndroid Build Coastguard Worker     translated->vertexBuffer.set(vertexBuffer);
406*8975f5c5SAndroid Build Coastguard Worker     translated->serial     = vertexBuffer->getSerial();
407*8975f5c5SAndroid Build Coastguard Worker     translated->baseOffset = streamOffset + firstElementOffset;
408*8975f5c5SAndroid Build Coastguard Worker 
409*8975f5c5SAndroid Build Coastguard Worker     // Instanced vertices do not apply the 'start' offset
410*8975f5c5SAndroid Build Coastguard Worker     translated->usesFirstVertexOffset = (binding.getDivisor() == 0);
411*8975f5c5SAndroid Build Coastguard Worker 
412*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
413*8975f5c5SAndroid Build Coastguard Worker }
414*8975f5c5SAndroid Build Coastguard Worker 
storeDynamicAttribs(const gl::Context * context,std::vector<TranslatedAttribute> * translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,GLint start,size_t count,GLsizei instances,GLuint baseInstance)415*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexDataManager::storeDynamicAttribs(
416*8975f5c5SAndroid Build Coastguard Worker     const gl::Context *context,
417*8975f5c5SAndroid Build Coastguard Worker     std::vector<TranslatedAttribute> *translatedAttribs,
418*8975f5c5SAndroid Build Coastguard Worker     const gl::AttributesMask &dynamicAttribsMask,
419*8975f5c5SAndroid Build Coastguard Worker     GLint start,
420*8975f5c5SAndroid Build Coastguard Worker     size_t count,
421*8975f5c5SAndroid Build Coastguard Worker     GLsizei instances,
422*8975f5c5SAndroid Build Coastguard Worker     GLuint baseInstance)
423*8975f5c5SAndroid Build Coastguard Worker {
424*8975f5c5SAndroid Build Coastguard Worker     // Instantiating this class will ensure the streaming buffer is never left mapped.
425*8975f5c5SAndroid Build Coastguard Worker     class StreamingBufferUnmapper final : NonCopyable
426*8975f5c5SAndroid Build Coastguard Worker     {
427*8975f5c5SAndroid Build Coastguard Worker       public:
428*8975f5c5SAndroid Build Coastguard Worker         StreamingBufferUnmapper(StreamingVertexBufferInterface *streamingBuffer)
429*8975f5c5SAndroid Build Coastguard Worker             : mStreamingBuffer(streamingBuffer)
430*8975f5c5SAndroid Build Coastguard Worker         {
431*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mStreamingBuffer);
432*8975f5c5SAndroid Build Coastguard Worker         }
433*8975f5c5SAndroid Build Coastguard Worker         ~StreamingBufferUnmapper() { mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); }
434*8975f5c5SAndroid Build Coastguard Worker 
435*8975f5c5SAndroid Build Coastguard Worker       private:
436*8975f5c5SAndroid Build Coastguard Worker         StreamingVertexBufferInterface *mStreamingBuffer;
437*8975f5c5SAndroid Build Coastguard Worker     };
438*8975f5c5SAndroid Build Coastguard Worker 
439*8975f5c5SAndroid Build Coastguard Worker     // Will trigger unmapping on return.
440*8975f5c5SAndroid Build Coastguard Worker     StreamingBufferUnmapper localUnmapper(&mStreamingBuffer);
441*8975f5c5SAndroid Build Coastguard Worker 
442*8975f5c5SAndroid Build Coastguard Worker     // Reserve the required space for the dynamic buffers.
443*8975f5c5SAndroid Build Coastguard Worker     for (auto attribIndex : dynamicAttribsMask)
444*8975f5c5SAndroid Build Coastguard Worker     {
445*8975f5c5SAndroid Build Coastguard Worker         const auto &dynamicAttrib = (*translatedAttribs)[attribIndex];
446*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(
447*8975f5c5SAndroid Build Coastguard Worker             reserveSpaceForAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
448*8975f5c5SAndroid Build Coastguard Worker     }
449*8975f5c5SAndroid Build Coastguard Worker 
450*8975f5c5SAndroid Build Coastguard Worker     // Store dynamic attributes
451*8975f5c5SAndroid Build Coastguard Worker     for (auto attribIndex : dynamicAttribsMask)
452*8975f5c5SAndroid Build Coastguard Worker     {
453*8975f5c5SAndroid Build Coastguard Worker         auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
454*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(
455*8975f5c5SAndroid Build Coastguard Worker             storeDynamicAttrib(context, dynamicAttrib, start, count, instances, baseInstance));
456*8975f5c5SAndroid Build Coastguard Worker     }
457*8975f5c5SAndroid Build Coastguard Worker 
458*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
459*8975f5c5SAndroid Build Coastguard Worker }
460*8975f5c5SAndroid Build Coastguard Worker 
PromoteDynamicAttribs(const gl::Context * context,const std::vector<TranslatedAttribute> & translatedAttribs,const gl::AttributesMask & dynamicAttribsMask,size_t count)461*8975f5c5SAndroid Build Coastguard Worker void VertexDataManager::PromoteDynamicAttribs(
462*8975f5c5SAndroid Build Coastguard Worker     const gl::Context *context,
463*8975f5c5SAndroid Build Coastguard Worker     const std::vector<TranslatedAttribute> &translatedAttribs,
464*8975f5c5SAndroid Build Coastguard Worker     const gl::AttributesMask &dynamicAttribsMask,
465*8975f5c5SAndroid Build Coastguard Worker     size_t count)
466*8975f5c5SAndroid Build Coastguard Worker {
467*8975f5c5SAndroid Build Coastguard Worker     for (auto attribIndex : dynamicAttribsMask)
468*8975f5c5SAndroid Build Coastguard Worker     {
469*8975f5c5SAndroid Build Coastguard Worker         const auto &dynamicAttrib = translatedAttribs[attribIndex];
470*8975f5c5SAndroid Build Coastguard Worker         ASSERT(dynamicAttrib.attribute && dynamicAttrib.binding);
471*8975f5c5SAndroid Build Coastguard Worker         const auto &binding = *dynamicAttrib.binding;
472*8975f5c5SAndroid Build Coastguard Worker 
473*8975f5c5SAndroid Build Coastguard Worker         gl::Buffer *buffer = binding.getBuffer().get();
474*8975f5c5SAndroid Build Coastguard Worker         if (buffer)
475*8975f5c5SAndroid Build Coastguard Worker         {
476*8975f5c5SAndroid Build Coastguard Worker             // Note: this multiplication can overflow. It should not be a security problem.
477*8975f5c5SAndroid Build Coastguard Worker             BufferD3D *bufferD3D = GetImplAs<BufferD3D>(buffer);
478*8975f5c5SAndroid Build Coastguard Worker             size_t typeSize      = ComputeVertexAttributeTypeSize(*dynamicAttrib.attribute);
479*8975f5c5SAndroid Build Coastguard Worker             bufferD3D->promoteStaticUsage(context, count * typeSize);
480*8975f5c5SAndroid Build Coastguard Worker         }
481*8975f5c5SAndroid Build Coastguard Worker     }
482*8975f5c5SAndroid Build Coastguard Worker }
483*8975f5c5SAndroid Build Coastguard Worker 
reserveSpaceForAttrib(const gl::Context * context,const TranslatedAttribute & translatedAttrib,GLint start,size_t count,GLsizei instances,GLuint baseInstance)484*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexDataManager::reserveSpaceForAttrib(const gl::Context *context,
485*8975f5c5SAndroid Build Coastguard Worker                                                        const TranslatedAttribute &translatedAttrib,
486*8975f5c5SAndroid Build Coastguard Worker                                                        GLint start,
487*8975f5c5SAndroid Build Coastguard Worker                                                        size_t count,
488*8975f5c5SAndroid Build Coastguard Worker                                                        GLsizei instances,
489*8975f5c5SAndroid Build Coastguard Worker                                                        GLuint baseInstance)
490*8975f5c5SAndroid Build Coastguard Worker {
491*8975f5c5SAndroid Build Coastguard Worker     ASSERT(translatedAttrib.attribute && translatedAttrib.binding);
492*8975f5c5SAndroid Build Coastguard Worker     const auto &attrib  = *translatedAttrib.attribute;
493*8975f5c5SAndroid Build Coastguard Worker     const auto &binding = *translatedAttrib.binding;
494*8975f5c5SAndroid Build Coastguard Worker 
495*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!DirectStoragePossible(context, attrib, binding));
496*8975f5c5SAndroid Build Coastguard Worker 
497*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer   = binding.getBuffer().get();
498*8975f5c5SAndroid Build Coastguard Worker     BufferD3D *bufferD3D = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
499*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!bufferD3D || bufferD3D->getStaticVertexBuffer(attrib, binding) == nullptr);
500*8975f5c5SAndroid Build Coastguard Worker 
501*8975f5c5SAndroid Build Coastguard Worker     // Make sure we always pass at least one instance count to gl::ComputeVertexBindingElementCount.
502*8975f5c5SAndroid Build Coastguard Worker     // Even if this is not an instanced draw call, some attributes can still be instanced if they
503*8975f5c5SAndroid Build Coastguard Worker     // have a non-zero divisor.
504*8975f5c5SAndroid Build Coastguard Worker     size_t totalCount = gl::ComputeVertexBindingElementCount(
505*8975f5c5SAndroid Build Coastguard Worker         binding.getDivisor(), count, static_cast<size_t>(std::max(instances, 1)));
506*8975f5c5SAndroid Build Coastguard Worker     // TODO([email protected]): force the index buffer to clamp any out of range indices instead
507*8975f5c5SAndroid Build Coastguard Worker     // of invalid operation here.
508*8975f5c5SAndroid Build Coastguard Worker     if (bufferD3D)
509*8975f5c5SAndroid Build Coastguard Worker     {
510*8975f5c5SAndroid Build Coastguard Worker         // Vertices do not apply the 'start' offset when the divisor is non-zero even when doing
511*8975f5c5SAndroid Build Coastguard Worker         // a non-instanced draw call
512*8975f5c5SAndroid Build Coastguard Worker         GLint firstVertexIndex = binding.getDivisor() > 0
513*8975f5c5SAndroid Build Coastguard Worker                                      ? UnsignedCeilDivide(baseInstance, binding.getDivisor())
514*8975f5c5SAndroid Build Coastguard Worker                                      : start;
515*8975f5c5SAndroid Build Coastguard Worker         int64_t maxVertexCount =
516*8975f5c5SAndroid Build Coastguard Worker             static_cast<int64_t>(firstVertexIndex) + static_cast<int64_t>(totalCount);
517*8975f5c5SAndroid Build Coastguard Worker 
518*8975f5c5SAndroid Build Coastguard Worker         int64_t maxByte = GetMaxAttributeByteOffsetForDraw(attrib, binding, maxVertexCount);
519*8975f5c5SAndroid Build Coastguard Worker 
520*8975f5c5SAndroid Build Coastguard Worker         ASSERT(bufferD3D->getSize() <= static_cast<size_t>(std::numeric_limits<int64_t>::max()));
521*8975f5c5SAndroid Build Coastguard Worker         ANGLE_CHECK(GetImplAs<ContextD3D>(context),
522*8975f5c5SAndroid Build Coastguard Worker                     maxByte <= static_cast<int64_t>(bufferD3D->getSize()),
523*8975f5c5SAndroid Build Coastguard Worker                     "Vertex buffer is not big enough for the draw call.", GL_INVALID_OPERATION);
524*8975f5c5SAndroid Build Coastguard Worker     }
525*8975f5c5SAndroid Build Coastguard Worker     return mStreamingBuffer.reserveVertexSpace(context, attrib, binding, totalCount, instances,
526*8975f5c5SAndroid Build Coastguard Worker                                                baseInstance);
527*8975f5c5SAndroid Build Coastguard Worker }
528*8975f5c5SAndroid Build Coastguard Worker 
storeDynamicAttrib(const gl::Context * context,TranslatedAttribute * translated,GLint start,size_t count,GLsizei instances,GLuint baseInstance)529*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexDataManager::storeDynamicAttrib(const gl::Context *context,
530*8975f5c5SAndroid Build Coastguard Worker                                                     TranslatedAttribute *translated,
531*8975f5c5SAndroid Build Coastguard Worker                                                     GLint start,
532*8975f5c5SAndroid Build Coastguard Worker                                                     size_t count,
533*8975f5c5SAndroid Build Coastguard Worker                                                     GLsizei instances,
534*8975f5c5SAndroid Build Coastguard Worker                                                     GLuint baseInstance)
535*8975f5c5SAndroid Build Coastguard Worker {
536*8975f5c5SAndroid Build Coastguard Worker     ASSERT(translated->attribute && translated->binding);
537*8975f5c5SAndroid Build Coastguard Worker     const auto &attrib  = *translated->attribute;
538*8975f5c5SAndroid Build Coastguard Worker     const auto &binding = *translated->binding;
539*8975f5c5SAndroid Build Coastguard Worker 
540*8975f5c5SAndroid Build Coastguard Worker     gl::Buffer *buffer = binding.getBuffer().get();
541*8975f5c5SAndroid Build Coastguard Worker     ASSERT(buffer || attrib.pointer);
542*8975f5c5SAndroid Build Coastguard Worker     ASSERT(attrib.enabled);
543*8975f5c5SAndroid Build Coastguard Worker 
544*8975f5c5SAndroid Build Coastguard Worker     BufferD3D *storage = buffer ? GetImplAs<BufferD3D>(buffer) : nullptr;
545*8975f5c5SAndroid Build Coastguard Worker 
546*8975f5c5SAndroid Build Coastguard Worker     // Instanced vertices do not apply the 'start' offset
547*8975f5c5SAndroid Build Coastguard Worker     GLint firstVertexIndex =
548*8975f5c5SAndroid Build Coastguard Worker         (binding.getDivisor() > 0 ? UnsignedCeilDivide(baseInstance, binding.getDivisor()) : start);
549*8975f5c5SAndroid Build Coastguard Worker 
550*8975f5c5SAndroid Build Coastguard Worker     // Compute source data pointer
551*8975f5c5SAndroid Build Coastguard Worker     const uint8_t *sourceData = nullptr;
552*8975f5c5SAndroid Build Coastguard Worker 
553*8975f5c5SAndroid Build Coastguard Worker     if (buffer)
554*8975f5c5SAndroid Build Coastguard Worker     {
555*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(storage->getData(context, &sourceData));
556*8975f5c5SAndroid Build Coastguard Worker         sourceData += static_cast<int>(ComputeVertexAttributeOffset(attrib, binding));
557*8975f5c5SAndroid Build Coastguard Worker     }
558*8975f5c5SAndroid Build Coastguard Worker     else
559*8975f5c5SAndroid Build Coastguard Worker     {
560*8975f5c5SAndroid Build Coastguard Worker         // Attributes using client memory ignore the VERTEX_ATTRIB_BINDING state.
561*8975f5c5SAndroid Build Coastguard Worker         // https://www.opengl.org/registry/specs/ARB/vertex_attrib_binding.txt
562*8975f5c5SAndroid Build Coastguard Worker         sourceData = static_cast<const uint8_t *>(attrib.pointer);
563*8975f5c5SAndroid Build Coastguard Worker     }
564*8975f5c5SAndroid Build Coastguard Worker 
565*8975f5c5SAndroid Build Coastguard Worker     unsigned int streamOffset = 0;
566*8975f5c5SAndroid Build Coastguard Worker 
567*8975f5c5SAndroid Build Coastguard Worker     translated->storage = nullptr;
568*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(
569*8975f5c5SAndroid Build Coastguard Worker         mFactory->getVertexSpaceRequired(context, attrib, binding, 1, 0, 0, &translated->stride));
570*8975f5c5SAndroid Build Coastguard Worker 
571*8975f5c5SAndroid Build Coastguard Worker     size_t totalCount = gl::ComputeVertexBindingElementCount(
572*8975f5c5SAndroid Build Coastguard Worker         binding.getDivisor(), count, static_cast<size_t>(std::max(instances, 1)));
573*8975f5c5SAndroid Build Coastguard Worker 
574*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(mStreamingBuffer.storeDynamicAttribute(
575*8975f5c5SAndroid Build Coastguard Worker         context, attrib, binding, translated->currentValueType, firstVertexIndex,
576*8975f5c5SAndroid Build Coastguard Worker         static_cast<GLsizei>(totalCount), instances, baseInstance, &streamOffset, sourceData));
577*8975f5c5SAndroid Build Coastguard Worker 
578*8975f5c5SAndroid Build Coastguard Worker     VertexBuffer *vertexBuffer = mStreamingBuffer.getVertexBuffer();
579*8975f5c5SAndroid Build Coastguard Worker 
580*8975f5c5SAndroid Build Coastguard Worker     translated->vertexBuffer.set(vertexBuffer);
581*8975f5c5SAndroid Build Coastguard Worker     translated->serial                = vertexBuffer->getSerial();
582*8975f5c5SAndroid Build Coastguard Worker     translated->baseOffset            = streamOffset;
583*8975f5c5SAndroid Build Coastguard Worker     translated->usesFirstVertexOffset = false;
584*8975f5c5SAndroid Build Coastguard Worker 
585*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
586*8975f5c5SAndroid Build Coastguard Worker }
587*8975f5c5SAndroid Build Coastguard Worker 
storeCurrentValue(const gl::Context * context,const gl::VertexAttribCurrentValueData & currentValue,TranslatedAttribute * translated,size_t attribIndex)588*8975f5c5SAndroid Build Coastguard Worker angle::Result VertexDataManager::storeCurrentValue(
589*8975f5c5SAndroid Build Coastguard Worker     const gl::Context *context,
590*8975f5c5SAndroid Build Coastguard Worker     const gl::VertexAttribCurrentValueData &currentValue,
591*8975f5c5SAndroid Build Coastguard Worker     TranslatedAttribute *translated,
592*8975f5c5SAndroid Build Coastguard Worker     size_t attribIndex)
593*8975f5c5SAndroid Build Coastguard Worker {
594*8975f5c5SAndroid Build Coastguard Worker     CurrentValueState *cachedState         = &mCurrentValueCache[attribIndex];
595*8975f5c5SAndroid Build Coastguard Worker     StreamingVertexBufferInterface &buffer = *cachedState->buffer;
596*8975f5c5SAndroid Build Coastguard Worker 
597*8975f5c5SAndroid Build Coastguard Worker     if (buffer.getBufferSize() == 0)
598*8975f5c5SAndroid Build Coastguard Worker     {
599*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(buffer.initialize(context, CONSTANT_VERTEX_BUFFER_SIZE));
600*8975f5c5SAndroid Build Coastguard Worker     }
601*8975f5c5SAndroid Build Coastguard Worker 
602*8975f5c5SAndroid Build Coastguard Worker     if (cachedState->data != currentValue)
603*8975f5c5SAndroid Build Coastguard Worker     {
604*8975f5c5SAndroid Build Coastguard Worker         ASSERT(translated->attribute && translated->binding);
605*8975f5c5SAndroid Build Coastguard Worker         const auto &attrib  = *translated->attribute;
606*8975f5c5SAndroid Build Coastguard Worker         const auto &binding = *translated->binding;
607*8975f5c5SAndroid Build Coastguard Worker 
608*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(buffer.reserveVertexSpace(context, attrib, binding, 1, 0, 0));
609*8975f5c5SAndroid Build Coastguard Worker 
610*8975f5c5SAndroid Build Coastguard Worker         const uint8_t *sourceData =
611*8975f5c5SAndroid Build Coastguard Worker             reinterpret_cast<const uint8_t *>(currentValue.Values.FloatValues);
612*8975f5c5SAndroid Build Coastguard Worker         unsigned int streamOffset;
613*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(buffer.storeDynamicAttribute(context, attrib, binding, currentValue.Type, 0, 1, 0,
614*8975f5c5SAndroid Build Coastguard Worker                                                0, &streamOffset, sourceData));
615*8975f5c5SAndroid Build Coastguard Worker 
616*8975f5c5SAndroid Build Coastguard Worker         buffer.getVertexBuffer()->hintUnmapResource();
617*8975f5c5SAndroid Build Coastguard Worker 
618*8975f5c5SAndroid Build Coastguard Worker         cachedState->data   = currentValue;
619*8975f5c5SAndroid Build Coastguard Worker         cachedState->offset = streamOffset;
620*8975f5c5SAndroid Build Coastguard Worker     }
621*8975f5c5SAndroid Build Coastguard Worker 
622*8975f5c5SAndroid Build Coastguard Worker     translated->vertexBuffer.set(buffer.getVertexBuffer());
623*8975f5c5SAndroid Build Coastguard Worker 
624*8975f5c5SAndroid Build Coastguard Worker     translated->storage               = nullptr;
625*8975f5c5SAndroid Build Coastguard Worker     translated->serial                = buffer.getSerial();
626*8975f5c5SAndroid Build Coastguard Worker     translated->divisor               = 0;
627*8975f5c5SAndroid Build Coastguard Worker     translated->stride                = 0;
628*8975f5c5SAndroid Build Coastguard Worker     translated->baseOffset            = static_cast<unsigned int>(cachedState->offset);
629*8975f5c5SAndroid Build Coastguard Worker     translated->usesFirstVertexOffset = false;
630*8975f5c5SAndroid Build Coastguard Worker 
631*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
632*8975f5c5SAndroid Build Coastguard Worker }
633*8975f5c5SAndroid Build Coastguard Worker 
634*8975f5c5SAndroid Build Coastguard Worker // VertexBufferBinding implementation
VertexBufferBinding()635*8975f5c5SAndroid Build Coastguard Worker VertexBufferBinding::VertexBufferBinding() : mBoundVertexBuffer(nullptr) {}
636*8975f5c5SAndroid Build Coastguard Worker 
VertexBufferBinding(const VertexBufferBinding & other)637*8975f5c5SAndroid Build Coastguard Worker VertexBufferBinding::VertexBufferBinding(const VertexBufferBinding &other)
638*8975f5c5SAndroid Build Coastguard Worker     : mBoundVertexBuffer(other.mBoundVertexBuffer)
639*8975f5c5SAndroid Build Coastguard Worker {
640*8975f5c5SAndroid Build Coastguard Worker     if (mBoundVertexBuffer)
641*8975f5c5SAndroid Build Coastguard Worker     {
642*8975f5c5SAndroid Build Coastguard Worker         mBoundVertexBuffer->addRef();
643*8975f5c5SAndroid Build Coastguard Worker     }
644*8975f5c5SAndroid Build Coastguard Worker }
645*8975f5c5SAndroid Build Coastguard Worker 
~VertexBufferBinding()646*8975f5c5SAndroid Build Coastguard Worker VertexBufferBinding::~VertexBufferBinding()
647*8975f5c5SAndroid Build Coastguard Worker {
648*8975f5c5SAndroid Build Coastguard Worker     if (mBoundVertexBuffer)
649*8975f5c5SAndroid Build Coastguard Worker     {
650*8975f5c5SAndroid Build Coastguard Worker         mBoundVertexBuffer->release();
651*8975f5c5SAndroid Build Coastguard Worker     }
652*8975f5c5SAndroid Build Coastguard Worker }
653*8975f5c5SAndroid Build Coastguard Worker 
operator =(const VertexBufferBinding & other)654*8975f5c5SAndroid Build Coastguard Worker VertexBufferBinding &VertexBufferBinding::operator=(const VertexBufferBinding &other)
655*8975f5c5SAndroid Build Coastguard Worker {
656*8975f5c5SAndroid Build Coastguard Worker     mBoundVertexBuffer = other.mBoundVertexBuffer;
657*8975f5c5SAndroid Build Coastguard Worker     if (mBoundVertexBuffer)
658*8975f5c5SAndroid Build Coastguard Worker     {
659*8975f5c5SAndroid Build Coastguard Worker         mBoundVertexBuffer->addRef();
660*8975f5c5SAndroid Build Coastguard Worker     }
661*8975f5c5SAndroid Build Coastguard Worker     return *this;
662*8975f5c5SAndroid Build Coastguard Worker }
663*8975f5c5SAndroid Build Coastguard Worker 
set(VertexBuffer * vertexBuffer)664*8975f5c5SAndroid Build Coastguard Worker void VertexBufferBinding::set(VertexBuffer *vertexBuffer)
665*8975f5c5SAndroid Build Coastguard Worker {
666*8975f5c5SAndroid Build Coastguard Worker     if (mBoundVertexBuffer == vertexBuffer)
667*8975f5c5SAndroid Build Coastguard Worker         return;
668*8975f5c5SAndroid Build Coastguard Worker 
669*8975f5c5SAndroid Build Coastguard Worker     if (mBoundVertexBuffer)
670*8975f5c5SAndroid Build Coastguard Worker     {
671*8975f5c5SAndroid Build Coastguard Worker         mBoundVertexBuffer->release();
672*8975f5c5SAndroid Build Coastguard Worker     }
673*8975f5c5SAndroid Build Coastguard Worker     if (vertexBuffer)
674*8975f5c5SAndroid Build Coastguard Worker     {
675*8975f5c5SAndroid Build Coastguard Worker         vertexBuffer->addRef();
676*8975f5c5SAndroid Build Coastguard Worker     }
677*8975f5c5SAndroid Build Coastguard Worker 
678*8975f5c5SAndroid Build Coastguard Worker     mBoundVertexBuffer = vertexBuffer;
679*8975f5c5SAndroid Build Coastguard Worker }
680*8975f5c5SAndroid Build Coastguard Worker 
get() const681*8975f5c5SAndroid Build Coastguard Worker VertexBuffer *VertexBufferBinding::get() const
682*8975f5c5SAndroid Build Coastguard Worker {
683*8975f5c5SAndroid Build Coastguard Worker     return mBoundVertexBuffer;
684*8975f5c5SAndroid Build Coastguard Worker }
685*8975f5c5SAndroid Build Coastguard Worker 
686*8975f5c5SAndroid Build Coastguard Worker }  // namespace rx
687