1*8975f5c5SAndroid Build Coastguard Worker// 2*8975f5c5SAndroid Build Coastguard Worker// Copyright 2019 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// VertexArrayMtl.mm: 7*8975f5c5SAndroid Build Coastguard Worker// Implements the class methods for VertexArrayMtl. 8*8975f5c5SAndroid Build Coastguard Worker// 9*8975f5c5SAndroid Build Coastguard Worker 10*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/VertexArrayMtl.h" 11*8975f5c5SAndroid Build Coastguard Worker 12*8975f5c5SAndroid Build Coastguard Worker#include <TargetConditionals.h> 13*8975f5c5SAndroid Build Coastguard Worker 14*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/BufferMtl.h" 15*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ContextMtl.h" 16*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/DisplayMtl.h" 17*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_format_utils.h" 18*8975f5c5SAndroid Build Coastguard Worker 19*8975f5c5SAndroid Build Coastguard Worker#include "common/debug.h" 20*8975f5c5SAndroid Build Coastguard Worker#include "common/utilities.h" 21*8975f5c5SAndroid Build Coastguard Worker 22*8975f5c5SAndroid Build Coastguard Workernamespace rx 23*8975f5c5SAndroid Build Coastguard Worker{ 24*8975f5c5SAndroid Build Coastguard Workernamespace 25*8975f5c5SAndroid Build Coastguard Worker{ 26*8975f5c5SAndroid Build Coastguard Workerconstexpr size_t kDynamicIndexDataSize = 1024 * 8; 27*8975f5c5SAndroid Build Coastguard Worker 28*8975f5c5SAndroid Build Coastguard Workerangle::Result StreamVertexData(ContextMtl *contextMtl, 29*8975f5c5SAndroid Build Coastguard Worker mtl::BufferPool *dynamicBuffer, 30*8975f5c5SAndroid Build Coastguard Worker const uint8_t *sourceData, 31*8975f5c5SAndroid Build Coastguard Worker size_t bytesToAllocate, 32*8975f5c5SAndroid Build Coastguard Worker size_t destOffset, 33*8975f5c5SAndroid Build Coastguard Worker size_t vertexCount, 34*8975f5c5SAndroid Build Coastguard Worker size_t stride, 35*8975f5c5SAndroid Build Coastguard Worker VertexCopyFunction vertexLoadFunction, 36*8975f5c5SAndroid Build Coastguard Worker SimpleWeakBufferHolderMtl *bufferHolder, 37*8975f5c5SAndroid Build Coastguard Worker size_t *bufferOffsetOut) 38*8975f5c5SAndroid Build Coastguard Worker{ 39*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK(contextMtl, vertexLoadFunction, "Unsupported format conversion", GL_INVALID_ENUM); 40*8975f5c5SAndroid Build Coastguard Worker uint8_t *dst = nullptr; 41*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef newBuffer; 42*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(dynamicBuffer->allocate(contextMtl, bytesToAllocate, &dst, &newBuffer, 43*8975f5c5SAndroid Build Coastguard Worker bufferOffsetOut, nullptr)); 44*8975f5c5SAndroid Build Coastguard Worker bufferHolder->set(newBuffer); 45*8975f5c5SAndroid Build Coastguard Worker dst += destOffset; 46*8975f5c5SAndroid Build Coastguard Worker vertexLoadFunction(sourceData, stride, vertexCount, dst); 47*8975f5c5SAndroid Build Coastguard Worker 48*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(dynamicBuffer->commit(contextMtl)); 49*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 50*8975f5c5SAndroid Build Coastguard Worker} 51*8975f5c5SAndroid Build Coastguard Worker 52*8975f5c5SAndroid Build Coastguard Workertemplate <typename SizeT> 53*8975f5c5SAndroid Build Coastguard Workerconst mtl::VertexFormat &GetVertexConversionFormat(ContextMtl *contextMtl, 54*8975f5c5SAndroid Build Coastguard Worker angle::FormatID originalFormat, 55*8975f5c5SAndroid Build Coastguard Worker SizeT *strideOut) 56*8975f5c5SAndroid Build Coastguard Worker{ 57*8975f5c5SAndroid Build Coastguard Worker // Convert to tightly packed format 58*8975f5c5SAndroid Build Coastguard Worker const mtl::VertexFormat &packedFormat = contextMtl->getVertexFormat(originalFormat, true); 59*8975f5c5SAndroid Build Coastguard Worker *strideOut = packedFormat.actualAngleFormat().pixelBytes; 60*8975f5c5SAndroid Build Coastguard Worker return packedFormat; 61*8975f5c5SAndroid Build Coastguard Worker} 62*8975f5c5SAndroid Build Coastguard Worker 63*8975f5c5SAndroid Build Coastguard Workersize_t GetIndexConvertedBufferSize(gl::DrawElementsType indexType, size_t indexCount) 64*8975f5c5SAndroid Build Coastguard Worker{ 65*8975f5c5SAndroid Build Coastguard Worker size_t elementSize = gl::GetDrawElementsTypeSize(indexType); 66*8975f5c5SAndroid Build Coastguard Worker if (indexType == gl::DrawElementsType::UnsignedByte) 67*8975f5c5SAndroid Build Coastguard Worker { 68*8975f5c5SAndroid Build Coastguard Worker // 8-bit indices are not supported by Metal, so they are promoted to 69*8975f5c5SAndroid Build Coastguard Worker // 16-bit indices below 70*8975f5c5SAndroid Build Coastguard Worker elementSize = sizeof(GLushort); 71*8975f5c5SAndroid Build Coastguard Worker } 72*8975f5c5SAndroid Build Coastguard Worker 73*8975f5c5SAndroid Build Coastguard Worker const size_t amount = elementSize * indexCount; 74*8975f5c5SAndroid Build Coastguard Worker 75*8975f5c5SAndroid Build Coastguard Worker return amount; 76*8975f5c5SAndroid Build Coastguard Worker} 77*8975f5c5SAndroid Build Coastguard Worker 78*8975f5c5SAndroid Build Coastguard Workerangle::Result StreamIndexData(ContextMtl *contextMtl, 79*8975f5c5SAndroid Build Coastguard Worker mtl::BufferPool *dynamicBuffer, 80*8975f5c5SAndroid Build Coastguard Worker const uint8_t *sourcePointer, 81*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType indexType, 82*8975f5c5SAndroid Build Coastguard Worker size_t indexCount, 83*8975f5c5SAndroid Build Coastguard Worker bool primitiveRestartEnabled, 84*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef *bufferOut, 85*8975f5c5SAndroid Build Coastguard Worker size_t *bufferOffsetOut) 86*8975f5c5SAndroid Build Coastguard Worker{ 87*8975f5c5SAndroid Build Coastguard Worker dynamicBuffer->releaseInFlightBuffers(contextMtl); 88*8975f5c5SAndroid Build Coastguard Worker const size_t amount = GetIndexConvertedBufferSize(indexType, indexCount); 89*8975f5c5SAndroid Build Coastguard Worker GLubyte *dst = nullptr; 90*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY( 91*8975f5c5SAndroid Build Coastguard Worker dynamicBuffer->allocate(contextMtl, amount, &dst, bufferOut, bufferOffsetOut, nullptr)); 92*8975f5c5SAndroid Build Coastguard Worker 93*8975f5c5SAndroid Build Coastguard Worker if (indexType == gl::DrawElementsType::UnsignedByte) 94*8975f5c5SAndroid Build Coastguard Worker { 95*8975f5c5SAndroid Build Coastguard Worker // Unsigned bytes don't have direct support in Metal so we have to expand the 96*8975f5c5SAndroid Build Coastguard Worker // memory to a GLushort. 97*8975f5c5SAndroid Build Coastguard Worker const GLubyte *in = static_cast<const GLubyte *>(sourcePointer); 98*8975f5c5SAndroid Build Coastguard Worker GLushort *expandedDst = reinterpret_cast<GLushort *>(dst); 99*8975f5c5SAndroid Build Coastguard Worker 100*8975f5c5SAndroid Build Coastguard Worker if (primitiveRestartEnabled) 101*8975f5c5SAndroid Build Coastguard Worker { 102*8975f5c5SAndroid Build Coastguard Worker for (size_t index = 0; index < indexCount; index++) 103*8975f5c5SAndroid Build Coastguard Worker { 104*8975f5c5SAndroid Build Coastguard Worker if (in[index] == 0xFF) 105*8975f5c5SAndroid Build Coastguard Worker { 106*8975f5c5SAndroid Build Coastguard Worker expandedDst[index] = 0xFFFF; 107*8975f5c5SAndroid Build Coastguard Worker } 108*8975f5c5SAndroid Build Coastguard Worker else 109*8975f5c5SAndroid Build Coastguard Worker { 110*8975f5c5SAndroid Build Coastguard Worker expandedDst[index] = static_cast<GLushort>(in[index]); 111*8975f5c5SAndroid Build Coastguard Worker } 112*8975f5c5SAndroid Build Coastguard Worker } 113*8975f5c5SAndroid Build Coastguard Worker } // if (primitiveRestartEnabled) 114*8975f5c5SAndroid Build Coastguard Worker else 115*8975f5c5SAndroid Build Coastguard Worker { 116*8975f5c5SAndroid Build Coastguard Worker for (size_t index = 0; index < indexCount; index++) 117*8975f5c5SAndroid Build Coastguard Worker { 118*8975f5c5SAndroid Build Coastguard Worker expandedDst[index] = static_cast<GLushort>(in[index]); 119*8975f5c5SAndroid Build Coastguard Worker } 120*8975f5c5SAndroid Build Coastguard Worker } // if (primitiveRestartEnabled) 121*8975f5c5SAndroid Build Coastguard Worker } 122*8975f5c5SAndroid Build Coastguard Worker else 123*8975f5c5SAndroid Build Coastguard Worker { 124*8975f5c5SAndroid Build Coastguard Worker memcpy(dst, sourcePointer, amount); 125*8975f5c5SAndroid Build Coastguard Worker } 126*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(dynamicBuffer->commit(contextMtl)); 127*8975f5c5SAndroid Build Coastguard Worker 128*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 129*8975f5c5SAndroid Build Coastguard Worker} 130*8975f5c5SAndroid Build Coastguard Worker 131*8975f5c5SAndroid Build Coastguard Workersize_t GetVertexCount(BufferMtl *srcBuffer, 132*8975f5c5SAndroid Build Coastguard Worker const gl::VertexBinding &binding, 133*8975f5c5SAndroid Build Coastguard Worker uint32_t srcFormatSize) 134*8975f5c5SAndroid Build Coastguard Worker{ 135*8975f5c5SAndroid Build Coastguard Worker // Bytes usable for vertex data. 136*8975f5c5SAndroid Build Coastguard Worker GLint64 bytes = srcBuffer->size() - binding.getOffset(); 137*8975f5c5SAndroid Build Coastguard Worker if (bytes < srcFormatSize) 138*8975f5c5SAndroid Build Coastguard Worker return 0; 139*8975f5c5SAndroid Build Coastguard Worker 140*8975f5c5SAndroid Build Coastguard Worker // Count the last vertex. It may occupy less than a full stride. 141*8975f5c5SAndroid Build Coastguard Worker size_t numVertices = 1; 142*8975f5c5SAndroid Build Coastguard Worker bytes -= srcFormatSize; 143*8975f5c5SAndroid Build Coastguard Worker 144*8975f5c5SAndroid Build Coastguard Worker // Count how many strides fit remaining space. 145*8975f5c5SAndroid Build Coastguard Worker if (bytes > 0) 146*8975f5c5SAndroid Build Coastguard Worker numVertices += static_cast<size_t>(bytes) / binding.getStride(); 147*8975f5c5SAndroid Build Coastguard Worker 148*8975f5c5SAndroid Build Coastguard Worker return numVertices; 149*8975f5c5SAndroid Build Coastguard Worker} 150*8975f5c5SAndroid Build Coastguard Worker 151*8975f5c5SAndroid Build Coastguard Workersize_t GetVertexCountWithConversion(BufferMtl *srcBuffer, 152*8975f5c5SAndroid Build Coastguard Worker VertexConversionBufferMtl *conversionBuffer, 153*8975f5c5SAndroid Build Coastguard Worker const gl::VertexBinding &binding, 154*8975f5c5SAndroid Build Coastguard Worker uint32_t srcFormatSize) 155*8975f5c5SAndroid Build Coastguard Worker{ 156*8975f5c5SAndroid Build Coastguard Worker // Bytes usable for vertex data. 157*8975f5c5SAndroid Build Coastguard Worker GLint64 bytes = srcBuffer->size() - 158*8975f5c5SAndroid Build Coastguard Worker MIN(static_cast<GLintptr>(conversionBuffer->offset), binding.getOffset()); 159*8975f5c5SAndroid Build Coastguard Worker if (bytes < srcFormatSize) 160*8975f5c5SAndroid Build Coastguard Worker return 0; 161*8975f5c5SAndroid Build Coastguard Worker 162*8975f5c5SAndroid Build Coastguard Worker // Count the last vertex. It may occupy less than a full stride. 163*8975f5c5SAndroid Build Coastguard Worker size_t numVertices = 1; 164*8975f5c5SAndroid Build Coastguard Worker bytes -= srcFormatSize; 165*8975f5c5SAndroid Build Coastguard Worker 166*8975f5c5SAndroid Build Coastguard Worker // Count how many strides fit remaining space. 167*8975f5c5SAndroid Build Coastguard Worker if (bytes > 0) 168*8975f5c5SAndroid Build Coastguard Worker numVertices += static_cast<size_t>(bytes) / binding.getStride(); 169*8975f5c5SAndroid Build Coastguard Worker 170*8975f5c5SAndroid Build Coastguard Worker return numVertices; 171*8975f5c5SAndroid Build Coastguard Worker} 172*8975f5c5SAndroid Build Coastguard Workerinline size_t GetIndexCount(BufferMtl *srcBuffer, size_t offset, gl::DrawElementsType indexType) 173*8975f5c5SAndroid Build Coastguard Worker{ 174*8975f5c5SAndroid Build Coastguard Worker size_t elementSize = gl::GetDrawElementsTypeSize(indexType); 175*8975f5c5SAndroid Build Coastguard Worker return (srcBuffer->size() - offset) / elementSize; 176*8975f5c5SAndroid Build Coastguard Worker} 177*8975f5c5SAndroid Build Coastguard Worker 178*8975f5c5SAndroid Build Coastguard Workerinline void SetDefaultVertexBufferLayout(mtl::VertexBufferLayoutDesc *layout) 179*8975f5c5SAndroid Build Coastguard Worker{ 180*8975f5c5SAndroid Build Coastguard Worker layout->stepFunction = mtl::kVertexStepFunctionInvalid; 181*8975f5c5SAndroid Build Coastguard Worker layout->stepRate = 0; 182*8975f5c5SAndroid Build Coastguard Worker layout->stride = 0; 183*8975f5c5SAndroid Build Coastguard Worker} 184*8975f5c5SAndroid Build Coastguard Worker 185*8975f5c5SAndroid Build Coastguard Workerinline MTLVertexFormat GetCurrentAttribFormat(GLenum type) 186*8975f5c5SAndroid Build Coastguard Worker{ 187*8975f5c5SAndroid Build Coastguard Worker switch (type) 188*8975f5c5SAndroid Build Coastguard Worker { 189*8975f5c5SAndroid Build Coastguard Worker case GL_INT: 190*8975f5c5SAndroid Build Coastguard Worker case GL_INT_VEC2: 191*8975f5c5SAndroid Build Coastguard Worker case GL_INT_VEC3: 192*8975f5c5SAndroid Build Coastguard Worker case GL_INT_VEC4: 193*8975f5c5SAndroid Build Coastguard Worker return MTLVertexFormatInt4; 194*8975f5c5SAndroid Build Coastguard Worker case GL_UNSIGNED_INT: 195*8975f5c5SAndroid Build Coastguard Worker case GL_UNSIGNED_INT_VEC2: 196*8975f5c5SAndroid Build Coastguard Worker case GL_UNSIGNED_INT_VEC3: 197*8975f5c5SAndroid Build Coastguard Worker case GL_UNSIGNED_INT_VEC4: 198*8975f5c5SAndroid Build Coastguard Worker return MTLVertexFormatUInt4; 199*8975f5c5SAndroid Build Coastguard Worker default: 200*8975f5c5SAndroid Build Coastguard Worker return MTLVertexFormatFloat4; 201*8975f5c5SAndroid Build Coastguard Worker } 202*8975f5c5SAndroid Build Coastguard Worker} 203*8975f5c5SAndroid Build Coastguard Worker 204*8975f5c5SAndroid Build Coastguard Worker} // namespace 205*8975f5c5SAndroid Build Coastguard Worker 206*8975f5c5SAndroid Build Coastguard Worker// VertexArrayMtl implementation 207*8975f5c5SAndroid Build Coastguard WorkerVertexArrayMtl::VertexArrayMtl(const gl::VertexArrayState &state, ContextMtl *context) 208*8975f5c5SAndroid Build Coastguard Worker : VertexArrayImpl(state), 209*8975f5c5SAndroid Build Coastguard Worker mDefaultFloatVertexFormat( 210*8975f5c5SAndroid Build Coastguard Worker context->getVertexFormat(angle::FormatID::R32G32B32A32_FLOAT, false)) 211*8975f5c5SAndroid Build Coastguard Worker{ 212*8975f5c5SAndroid Build Coastguard Worker reset(context); 213*8975f5c5SAndroid Build Coastguard Worker 214*8975f5c5SAndroid Build Coastguard Worker mDynamicVertexData.initialize(context, 0, mtl::kVertexAttribBufferStrideAlignment, 215*8975f5c5SAndroid Build Coastguard Worker /** maxBuffers */ 10 * mtl::kMaxVertexAttribs); 216*8975f5c5SAndroid Build Coastguard Worker 217*8975f5c5SAndroid Build Coastguard Worker mDynamicIndexData.initialize(context, kDynamicIndexDataSize, mtl::kIndexBufferOffsetAlignment, 218*8975f5c5SAndroid Build Coastguard Worker 0); 219*8975f5c5SAndroid Build Coastguard Worker} 220*8975f5c5SAndroid Build Coastguard WorkerVertexArrayMtl::~VertexArrayMtl() {} 221*8975f5c5SAndroid Build Coastguard Worker 222*8975f5c5SAndroid Build Coastguard Workervoid VertexArrayMtl::destroy(const gl::Context *context) 223*8975f5c5SAndroid Build Coastguard Worker{ 224*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 225*8975f5c5SAndroid Build Coastguard Worker 226*8975f5c5SAndroid Build Coastguard Worker reset(contextMtl); 227*8975f5c5SAndroid Build Coastguard Worker 228*8975f5c5SAndroid Build Coastguard Worker mDynamicVertexData.destroy(contextMtl); 229*8975f5c5SAndroid Build Coastguard Worker mDynamicIndexData.destroy(contextMtl); 230*8975f5c5SAndroid Build Coastguard Worker} 231*8975f5c5SAndroid Build Coastguard Worker 232*8975f5c5SAndroid Build Coastguard Workervoid VertexArrayMtl::reset(ContextMtl *context) 233*8975f5c5SAndroid Build Coastguard Worker{ 234*8975f5c5SAndroid Build Coastguard Worker for (BufferHolderMtl *&buffer : mCurrentArrayBuffers) 235*8975f5c5SAndroid Build Coastguard Worker { 236*8975f5c5SAndroid Build Coastguard Worker buffer = nullptr; 237*8975f5c5SAndroid Build Coastguard Worker } 238*8975f5c5SAndroid Build Coastguard Worker for (size_t &offset : mCurrentArrayBufferOffsets) 239*8975f5c5SAndroid Build Coastguard Worker { 240*8975f5c5SAndroid Build Coastguard Worker offset = 0; 241*8975f5c5SAndroid Build Coastguard Worker } 242*8975f5c5SAndroid Build Coastguard Worker for (GLuint &stride : mCurrentArrayBufferStrides) 243*8975f5c5SAndroid Build Coastguard Worker { 244*8975f5c5SAndroid Build Coastguard Worker stride = 0; 245*8975f5c5SAndroid Build Coastguard Worker } 246*8975f5c5SAndroid Build Coastguard Worker for (const mtl::VertexFormat *&format : mCurrentArrayBufferFormats) 247*8975f5c5SAndroid Build Coastguard Worker { 248*8975f5c5SAndroid Build Coastguard Worker format = &mDefaultFloatVertexFormat; 249*8975f5c5SAndroid Build Coastguard Worker } 250*8975f5c5SAndroid Build Coastguard Worker 251*8975f5c5SAndroid Build Coastguard Worker for (size_t &inlineDataSize : mCurrentArrayInlineDataSizes) 252*8975f5c5SAndroid Build Coastguard Worker { 253*8975f5c5SAndroid Build Coastguard Worker inlineDataSize = 0; 254*8975f5c5SAndroid Build Coastguard Worker } 255*8975f5c5SAndroid Build Coastguard Worker 256*8975f5c5SAndroid Build Coastguard Worker for (angle::MemoryBuffer &convertedClientArray : mConvertedClientSmallArrays) 257*8975f5c5SAndroid Build Coastguard Worker { 258*8975f5c5SAndroid Build Coastguard Worker convertedClientArray.clear(); 259*8975f5c5SAndroid Build Coastguard Worker } 260*8975f5c5SAndroid Build Coastguard Worker 261*8975f5c5SAndroid Build Coastguard Worker for (const uint8_t *&clientPointer : mCurrentArrayInlineDataPointers) 262*8975f5c5SAndroid Build Coastguard Worker { 263*8975f5c5SAndroid Build Coastguard Worker clientPointer = nullptr; 264*8975f5c5SAndroid Build Coastguard Worker } 265*8975f5c5SAndroid Build Coastguard Worker 266*8975f5c5SAndroid Build Coastguard Worker if (context->getDisplay()->getFeatures().allowInlineConstVertexData.enabled) 267*8975f5c5SAndroid Build Coastguard Worker { 268*8975f5c5SAndroid Build Coastguard Worker mInlineDataMaxSize = mtl::kInlineConstDataMaxSize; 269*8975f5c5SAndroid Build Coastguard Worker } 270*8975f5c5SAndroid Build Coastguard Worker else 271*8975f5c5SAndroid Build Coastguard Worker { 272*8975f5c5SAndroid Build Coastguard Worker mInlineDataMaxSize = 0; 273*8975f5c5SAndroid Build Coastguard Worker } 274*8975f5c5SAndroid Build Coastguard Worker 275*8975f5c5SAndroid Build Coastguard Worker mVertexArrayDirty = true; 276*8975f5c5SAndroid Build Coastguard Worker} 277*8975f5c5SAndroid Build Coastguard Worker 278*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::syncState(const gl::Context *context, 279*8975f5c5SAndroid Build Coastguard Worker const gl::VertexArray::DirtyBits &dirtyBits, 280*8975f5c5SAndroid Build Coastguard Worker gl::VertexArray::DirtyAttribBitsArray *attribBits, 281*8975f5c5SAndroid Build Coastguard Worker gl::VertexArray::DirtyBindingBitsArray *bindingBits) 282*8975f5c5SAndroid Build Coastguard Worker{ 283*8975f5c5SAndroid Build Coastguard Worker const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes(); 284*8975f5c5SAndroid Build Coastguard Worker const std::vector<gl::VertexBinding> &bindings = mState.getVertexBindings(); 285*8975f5c5SAndroid Build Coastguard Worker 286*8975f5c5SAndroid Build Coastguard Worker for (auto iter = dirtyBits.begin(), endIter = dirtyBits.end(); iter != endIter; ++iter) 287*8975f5c5SAndroid Build Coastguard Worker { 288*8975f5c5SAndroid Build Coastguard Worker size_t dirtyBit = *iter; 289*8975f5c5SAndroid Build Coastguard Worker switch (dirtyBit) 290*8975f5c5SAndroid Build Coastguard Worker { 291*8975f5c5SAndroid Build Coastguard Worker case gl::VertexArray::DIRTY_BIT_LOST_OBSERVATION: 292*8975f5c5SAndroid Build Coastguard Worker { 293*8975f5c5SAndroid Build Coastguard Worker // If vertex array was not observing while unbound, we need to check buffer's 294*8975f5c5SAndroid Build Coastguard Worker // internal storage and take action if buffer has changed while not observing. 295*8975f5c5SAndroid Build Coastguard Worker // For now we just simply assume buffer storage has changed and always dirty all 296*8975f5c5SAndroid Build Coastguard Worker // binding points. 297*8975f5c5SAndroid Build Coastguard Worker iter.setLaterBits( 298*8975f5c5SAndroid Build Coastguard Worker gl::VertexArray::DirtyBits(mState.getBufferBindingMask().to_ulong() 299*8975f5c5SAndroid Build Coastguard Worker << gl::VertexArray::DIRTY_BIT_BINDING_0)); 300*8975f5c5SAndroid Build Coastguard Worker break; 301*8975f5c5SAndroid Build Coastguard Worker } 302*8975f5c5SAndroid Build Coastguard Worker 303*8975f5c5SAndroid Build Coastguard Worker case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER: 304*8975f5c5SAndroid Build Coastguard Worker case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA: 305*8975f5c5SAndroid Build Coastguard Worker { 306*8975f5c5SAndroid Build Coastguard Worker mVertexDataDirty = true; 307*8975f5c5SAndroid Build Coastguard Worker break; 308*8975f5c5SAndroid Build Coastguard Worker } 309*8975f5c5SAndroid Build Coastguard Worker 310*8975f5c5SAndroid Build Coastguard Worker#define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \ 311*8975f5c5SAndroid Build Coastguard Worker case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \ 312*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(syncDirtyAttrib(context, attribs[INDEX], bindings[attribs[INDEX].bindingIndex], \ 313*8975f5c5SAndroid Build Coastguard Worker INDEX)); \ 314*8975f5c5SAndroid Build Coastguard Worker mVertexArrayDirty = true; \ 315*8975f5c5SAndroid Build Coastguard Worker (*attribBits)[INDEX].reset(); \ 316*8975f5c5SAndroid Build Coastguard Worker break; 317*8975f5c5SAndroid Build Coastguard Worker 318*8975f5c5SAndroid Build Coastguard Worker ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC) 319*8975f5c5SAndroid Build Coastguard Worker 320*8975f5c5SAndroid Build Coastguard Worker#define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \ 321*8975f5c5SAndroid Build Coastguard Worker case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \ 322*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(syncDirtyAttrib(context, attribs[INDEX], bindings[attribs[INDEX].bindingIndex], \ 323*8975f5c5SAndroid Build Coastguard Worker INDEX)); \ 324*8975f5c5SAndroid Build Coastguard Worker mVertexArrayDirty = true; \ 325*8975f5c5SAndroid Build Coastguard Worker (*bindingBits)[INDEX].reset(); \ 326*8975f5c5SAndroid Build Coastguard Worker break; 327*8975f5c5SAndroid Build Coastguard Worker 328*8975f5c5SAndroid Build Coastguard Worker ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC) 329*8975f5c5SAndroid Build Coastguard Worker 330*8975f5c5SAndroid Build Coastguard Worker#define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \ 331*8975f5c5SAndroid Build Coastguard Worker case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \ 332*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(syncDirtyAttrib(context, attribs[INDEX], bindings[attribs[INDEX].bindingIndex], \ 333*8975f5c5SAndroid Build Coastguard Worker INDEX)); \ 334*8975f5c5SAndroid Build Coastguard Worker mVertexDataDirty = true; \ 335*8975f5c5SAndroid Build Coastguard Worker break; 336*8975f5c5SAndroid Build Coastguard Worker 337*8975f5c5SAndroid Build Coastguard Worker ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC) 338*8975f5c5SAndroid Build Coastguard Worker 339*8975f5c5SAndroid Build Coastguard Worker default: 340*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 341*8975f5c5SAndroid Build Coastguard Worker break; 342*8975f5c5SAndroid Build Coastguard Worker } 343*8975f5c5SAndroid Build Coastguard Worker } 344*8975f5c5SAndroid Build Coastguard Worker 345*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 346*8975f5c5SAndroid Build Coastguard Worker} 347*8975f5c5SAndroid Build Coastguard Worker 348*8975f5c5SAndroid Build Coastguard Worker// vertexDescChanged is both input and output, the input value if is true, will force new 349*8975f5c5SAndroid Build Coastguard Worker// mtl::VertexDesc to be returned via vertexDescOut. This typically happens when active shader 350*8975f5c5SAndroid Build Coastguard Worker// program is changed. 351*8975f5c5SAndroid Build Coastguard Worker// Otherwise, it is only returned when the vertex array is dirty. 352*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::setupDraw(const gl::Context *glContext, 353*8975f5c5SAndroid Build Coastguard Worker mtl::RenderCommandEncoder *cmdEncoder, 354*8975f5c5SAndroid Build Coastguard Worker bool *vertexDescChanged, 355*8975f5c5SAndroid Build Coastguard Worker mtl::VertexDesc *vertexDescOut) 356*8975f5c5SAndroid Build Coastguard Worker{ 357*8975f5c5SAndroid Build Coastguard Worker // NOTE(hqle): consider only updating dirty attributes 358*8975f5c5SAndroid Build Coastguard Worker bool dirty = mVertexArrayDirty || *vertexDescChanged; 359*8975f5c5SAndroid Build Coastguard Worker 360*8975f5c5SAndroid Build Coastguard Worker if (dirty) 361*8975f5c5SAndroid Build Coastguard Worker { 362*8975f5c5SAndroid Build Coastguard Worker 363*8975f5c5SAndroid Build Coastguard Worker mVertexArrayDirty = false; 364*8975f5c5SAndroid Build Coastguard Worker mEmulatedInstanceAttribs.clear(); 365*8975f5c5SAndroid Build Coastguard Worker 366*8975f5c5SAndroid Build Coastguard Worker const gl::ProgramExecutable *executable = glContext->getState().getProgramExecutable(); 367*8975f5c5SAndroid Build Coastguard Worker const gl::AttributesMask &programActiveAttribsMask = 368*8975f5c5SAndroid Build Coastguard Worker executable->getActiveAttribLocationsMask(); 369*8975f5c5SAndroid Build Coastguard Worker 370*8975f5c5SAndroid Build Coastguard Worker const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes(); 371*8975f5c5SAndroid Build Coastguard Worker const std::vector<gl::VertexBinding> &bindings = mState.getVertexBindings(); 372*8975f5c5SAndroid Build Coastguard Worker 373*8975f5c5SAndroid Build Coastguard Worker mtl::VertexDesc &desc = *vertexDescOut; 374*8975f5c5SAndroid Build Coastguard Worker 375*8975f5c5SAndroid Build Coastguard Worker desc.numAttribs = mtl::kMaxVertexAttribs; 376*8975f5c5SAndroid Build Coastguard Worker desc.numBufferLayouts = mtl::kMaxVertexAttribs; 377*8975f5c5SAndroid Build Coastguard Worker 378*8975f5c5SAndroid Build Coastguard Worker // Initialize the buffer layouts with constant step rate 379*8975f5c5SAndroid Build Coastguard Worker for (uint32_t b = 0; b < mtl::kMaxVertexAttribs; ++b) 380*8975f5c5SAndroid Build Coastguard Worker { 381*8975f5c5SAndroid Build Coastguard Worker SetDefaultVertexBufferLayout(&desc.layouts[b]); 382*8975f5c5SAndroid Build Coastguard Worker } 383*8975f5c5SAndroid Build Coastguard Worker 384*8975f5c5SAndroid Build Coastguard Worker // Cache vertex shader input types 385*8975f5c5SAndroid Build Coastguard Worker std::array<uint8_t, mtl::kMaxVertexAttribs> currentAttribFormats{}; 386*8975f5c5SAndroid Build Coastguard Worker for (auto &input : executable->getProgramInputs()) 387*8975f5c5SAndroid Build Coastguard Worker { 388*8975f5c5SAndroid Build Coastguard Worker ASSERT(input.getLocation() != -1); 389*8975f5c5SAndroid Build Coastguard Worker ASSERT(input.getLocation() < static_cast<int>(mtl::kMaxVertexAttribs)); 390*8975f5c5SAndroid Build Coastguard Worker currentAttribFormats[input.getLocation()] = GetCurrentAttribFormat(input.getType()); 391*8975f5c5SAndroid Build Coastguard Worker } 392*8975f5c5SAndroid Build Coastguard Worker MTLVertexFormat currentAttribFormat = MTLVertexFormatInvalid; 393*8975f5c5SAndroid Build Coastguard Worker 394*8975f5c5SAndroid Build Coastguard Worker for (uint32_t v = 0; v < mtl::kMaxVertexAttribs; ++v) 395*8975f5c5SAndroid Build Coastguard Worker { 396*8975f5c5SAndroid Build Coastguard Worker if (!programActiveAttribsMask.test(v)) 397*8975f5c5SAndroid Build Coastguard Worker { 398*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].format = MTLVertexFormatInvalid; 399*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].bufferIndex = 0; 400*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].offset = 0; 401*8975f5c5SAndroid Build Coastguard Worker continue; 402*8975f5c5SAndroid Build Coastguard Worker } 403*8975f5c5SAndroid Build Coastguard Worker 404*8975f5c5SAndroid Build Coastguard Worker const auto &attrib = attribs[v]; 405*8975f5c5SAndroid Build Coastguard Worker const gl::VertexBinding &binding = bindings[attrib.bindingIndex]; 406*8975f5c5SAndroid Build Coastguard Worker 407*8975f5c5SAndroid Build Coastguard Worker bool attribEnabled = attrib.enabled; 408*8975f5c5SAndroid Build Coastguard Worker if (attribEnabled && 409*8975f5c5SAndroid Build Coastguard Worker !(mCurrentArrayBuffers[v] && mCurrentArrayBuffers[v]->getCurrentBuffer()) && 410*8975f5c5SAndroid Build Coastguard Worker !mCurrentArrayInlineDataPointers[v]) 411*8975f5c5SAndroid Build Coastguard Worker { 412*8975f5c5SAndroid Build Coastguard Worker // Disable it to avoid crash. 413*8975f5c5SAndroid Build Coastguard Worker attribEnabled = false; 414*8975f5c5SAndroid Build Coastguard Worker } 415*8975f5c5SAndroid Build Coastguard Worker 416*8975f5c5SAndroid Build Coastguard Worker if (currentAttribFormats[v] != MTLVertexFormatInvalid) 417*8975f5c5SAndroid Build Coastguard Worker { 418*8975f5c5SAndroid Build Coastguard Worker currentAttribFormat = static_cast<MTLVertexFormat>(currentAttribFormats[v]); 419*8975f5c5SAndroid Build Coastguard Worker } 420*8975f5c5SAndroid Build Coastguard Worker else 421*8975f5c5SAndroid Build Coastguard Worker { 422*8975f5c5SAndroid Build Coastguard Worker // This is a non-first matrix column 423*8975f5c5SAndroid Build Coastguard Worker ASSERT(currentAttribFormat != MTLVertexFormatInvalid); 424*8975f5c5SAndroid Build Coastguard Worker } 425*8975f5c5SAndroid Build Coastguard Worker 426*8975f5c5SAndroid Build Coastguard Worker if (!attribEnabled) 427*8975f5c5SAndroid Build Coastguard Worker { 428*8975f5c5SAndroid Build Coastguard Worker // Use default attribute 429*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].bufferIndex = mtl::kDefaultAttribsBindingIndex; 430*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].offset = v * mtl::kDefaultAttributeSize; 431*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].format = currentAttribFormat; 432*8975f5c5SAndroid Build Coastguard Worker } 433*8975f5c5SAndroid Build Coastguard Worker else 434*8975f5c5SAndroid Build Coastguard Worker { 435*8975f5c5SAndroid Build Coastguard Worker uint32_t bufferIdx = mtl::kVboBindingIndexStart + v; 436*8975f5c5SAndroid Build Coastguard Worker uint32_t bufferOffset = static_cast<uint32_t>(mCurrentArrayBufferOffsets[v]); 437*8975f5c5SAndroid Build Coastguard Worker 438*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].format = mCurrentArrayBufferFormats[v]->metalFormat; 439*8975f5c5SAndroid Build Coastguard Worker 440*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].bufferIndex = bufferIdx; 441*8975f5c5SAndroid Build Coastguard Worker desc.attributes[v].offset = 0; 442*8975f5c5SAndroid Build Coastguard Worker ASSERT((bufferOffset % mtl::kVertexAttribBufferStrideAlignment) == 0); 443*8975f5c5SAndroid Build Coastguard Worker 444*8975f5c5SAndroid Build Coastguard Worker ASSERT(bufferIdx < mtl::kMaxVertexAttribs); 445*8975f5c5SAndroid Build Coastguard Worker if (binding.getDivisor() == 0) 446*8975f5c5SAndroid Build Coastguard Worker { 447*8975f5c5SAndroid Build Coastguard Worker desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionPerVertex; 448*8975f5c5SAndroid Build Coastguard Worker desc.layouts[bufferIdx].stepRate = 1; 449*8975f5c5SAndroid Build Coastguard Worker } 450*8975f5c5SAndroid Build Coastguard Worker else 451*8975f5c5SAndroid Build Coastguard Worker { 452*8975f5c5SAndroid Build Coastguard Worker desc.layouts[bufferIdx].stepFunction = MTLVertexStepFunctionPerInstance; 453*8975f5c5SAndroid Build Coastguard Worker desc.layouts[bufferIdx].stepRate = binding.getDivisor(); 454*8975f5c5SAndroid Build Coastguard Worker } 455*8975f5c5SAndroid Build Coastguard Worker 456*8975f5c5SAndroid Build Coastguard Worker // Metal does not allow the sum of the buffer binding 457*8975f5c5SAndroid Build Coastguard Worker // offset and the vertex layout stride to be greater 458*8975f5c5SAndroid Build Coastguard Worker // than the buffer length. 459*8975f5c5SAndroid Build Coastguard Worker // In OpenGL, this is valid only when a draw call accesses just 460*8975f5c5SAndroid Build Coastguard Worker // one vertex, so just replace the stride with the format size. 461*8975f5c5SAndroid Build Coastguard Worker uint32_t stride = mCurrentArrayBufferStrides[v]; 462*8975f5c5SAndroid Build Coastguard Worker if (mCurrentArrayBuffers[v]) 463*8975f5c5SAndroid Build Coastguard Worker { 464*8975f5c5SAndroid Build Coastguard Worker const size_t length = mCurrentArrayBuffers[v]->getCurrentBuffer()->size(); 465*8975f5c5SAndroid Build Coastguard Worker const size_t offset = mCurrentArrayBufferOffsets[v]; 466*8975f5c5SAndroid Build Coastguard Worker ASSERT(offset < length); 467*8975f5c5SAndroid Build Coastguard Worker if (length - offset < stride) 468*8975f5c5SAndroid Build Coastguard Worker { 469*8975f5c5SAndroid Build Coastguard Worker stride = mCurrentArrayBufferFormats[v]->actualAngleFormat().pixelBytes; 470*8975f5c5SAndroid Build Coastguard Worker ASSERT(stride % mtl::kVertexAttribBufferStrideAlignment == 0); 471*8975f5c5SAndroid Build Coastguard Worker } 472*8975f5c5SAndroid Build Coastguard Worker } 473*8975f5c5SAndroid Build Coastguard Worker desc.layouts[bufferIdx].stride = stride; 474*8975f5c5SAndroid Build Coastguard Worker } 475*8975f5c5SAndroid Build Coastguard Worker } // for (v) 476*8975f5c5SAndroid Build Coastguard Worker } 477*8975f5c5SAndroid Build Coastguard Worker 478*8975f5c5SAndroid Build Coastguard Worker if (dirty || mVertexDataDirty) 479*8975f5c5SAndroid Build Coastguard Worker { 480*8975f5c5SAndroid Build Coastguard Worker mVertexDataDirty = false; 481*8975f5c5SAndroid Build Coastguard Worker const gl::ProgramExecutable *executable = glContext->getState().getProgramExecutable(); 482*8975f5c5SAndroid Build Coastguard Worker const gl::AttributesMask &programActiveAttribsMask = 483*8975f5c5SAndroid Build Coastguard Worker executable->getActiveAttribLocationsMask(); 484*8975f5c5SAndroid Build Coastguard Worker 485*8975f5c5SAndroid Build Coastguard Worker for (uint32_t v = 0; v < mtl::kMaxVertexAttribs; ++v) 486*8975f5c5SAndroid Build Coastguard Worker { 487*8975f5c5SAndroid Build Coastguard Worker if (!programActiveAttribsMask.test(v)) 488*8975f5c5SAndroid Build Coastguard Worker { 489*8975f5c5SAndroid Build Coastguard Worker continue; 490*8975f5c5SAndroid Build Coastguard Worker } 491*8975f5c5SAndroid Build Coastguard Worker uint32_t bufferIdx = mtl::kVboBindingIndexStart + v; 492*8975f5c5SAndroid Build Coastguard Worker uint32_t bufferOffset = static_cast<uint32_t>(mCurrentArrayBufferOffsets[v]); 493*8975f5c5SAndroid Build Coastguard Worker if (mCurrentArrayBuffers[v]) 494*8975f5c5SAndroid Build Coastguard Worker { 495*8975f5c5SAndroid Build Coastguard Worker cmdEncoder->setVertexBuffer(mCurrentArrayBuffers[v]->getCurrentBuffer(), 496*8975f5c5SAndroid Build Coastguard Worker bufferOffset, bufferIdx); 497*8975f5c5SAndroid Build Coastguard Worker } 498*8975f5c5SAndroid Build Coastguard Worker else if (mCurrentArrayInlineDataPointers[v]) 499*8975f5c5SAndroid Build Coastguard Worker { 500*8975f5c5SAndroid Build Coastguard Worker // No buffer specified, use the client memory directly as inline constant data 501*8975f5c5SAndroid Build Coastguard Worker ASSERT(mCurrentArrayInlineDataSizes[v] <= mInlineDataMaxSize); 502*8975f5c5SAndroid Build Coastguard Worker cmdEncoder->setVertexBytes(mCurrentArrayInlineDataPointers[v], 503*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayInlineDataSizes[v], bufferIdx); 504*8975f5c5SAndroid Build Coastguard Worker } 505*8975f5c5SAndroid Build Coastguard Worker } 506*8975f5c5SAndroid Build Coastguard Worker } 507*8975f5c5SAndroid Build Coastguard Worker 508*8975f5c5SAndroid Build Coastguard Worker *vertexDescChanged = dirty; 509*8975f5c5SAndroid Build Coastguard Worker 510*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 511*8975f5c5SAndroid Build Coastguard Worker} 512*8975f5c5SAndroid Build Coastguard Worker 513*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::updateClientAttribs(const gl::Context *context, 514*8975f5c5SAndroid Build Coastguard Worker GLint firstVertex, 515*8975f5c5SAndroid Build Coastguard Worker GLsizei vertexOrIndexCount, 516*8975f5c5SAndroid Build Coastguard Worker GLsizei instanceCount, 517*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType indexTypeOrInvalid, 518*8975f5c5SAndroid Build Coastguard Worker const void *indices) 519*8975f5c5SAndroid Build Coastguard Worker{ 520*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 521*8975f5c5SAndroid Build Coastguard Worker const gl::AttributesMask &clientAttribs = context->getStateCache().getActiveClientAttribsMask(); 522*8975f5c5SAndroid Build Coastguard Worker 523*8975f5c5SAndroid Build Coastguard Worker ASSERT(clientAttribs.any()); 524*8975f5c5SAndroid Build Coastguard Worker 525*8975f5c5SAndroid Build Coastguard Worker GLint startVertex; 526*8975f5c5SAndroid Build Coastguard Worker size_t vertexCount; 527*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(GetVertexRangeInfo(context, firstVertex, vertexOrIndexCount, indexTypeOrInvalid, 528*8975f5c5SAndroid Build Coastguard Worker indices, 0, &startVertex, &vertexCount)); 529*8975f5c5SAndroid Build Coastguard Worker 530*8975f5c5SAndroid Build Coastguard Worker mDynamicVertexData.releaseInFlightBuffers(contextMtl); 531*8975f5c5SAndroid Build Coastguard Worker 532*8975f5c5SAndroid Build Coastguard Worker const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes(); 533*8975f5c5SAndroid Build Coastguard Worker const std::vector<gl::VertexBinding> &bindings = mState.getVertexBindings(); 534*8975f5c5SAndroid Build Coastguard Worker 535*8975f5c5SAndroid Build Coastguard Worker for (size_t attribIndex : clientAttribs) 536*8975f5c5SAndroid Build Coastguard Worker { 537*8975f5c5SAndroid Build Coastguard Worker const gl::VertexAttribute &attrib = attribs[attribIndex]; 538*8975f5c5SAndroid Build Coastguard Worker const gl::VertexBinding &binding = bindings[attrib.bindingIndex]; 539*8975f5c5SAndroid Build Coastguard Worker ASSERT(attrib.enabled && binding.getBuffer().get() == nullptr); 540*8975f5c5SAndroid Build Coastguard Worker 541*8975f5c5SAndroid Build Coastguard Worker // Source client memory pointer 542*8975f5c5SAndroid Build Coastguard Worker const uint8_t *src = static_cast<const uint8_t *>(attrib.pointer); 543*8975f5c5SAndroid Build Coastguard Worker ASSERT(src); 544*8975f5c5SAndroid Build Coastguard Worker 545*8975f5c5SAndroid Build Coastguard Worker GLint startElement; 546*8975f5c5SAndroid Build Coastguard Worker size_t elementCount; 547*8975f5c5SAndroid Build Coastguard Worker if (binding.getDivisor() == 0) 548*8975f5c5SAndroid Build Coastguard Worker { 549*8975f5c5SAndroid Build Coastguard Worker // Per vertex attribute 550*8975f5c5SAndroid Build Coastguard Worker startElement = startVertex; 551*8975f5c5SAndroid Build Coastguard Worker elementCount = vertexCount; 552*8975f5c5SAndroid Build Coastguard Worker } 553*8975f5c5SAndroid Build Coastguard Worker else 554*8975f5c5SAndroid Build Coastguard Worker { 555*8975f5c5SAndroid Build Coastguard Worker // Per instance attribute 556*8975f5c5SAndroid Build Coastguard Worker startElement = 0; 557*8975f5c5SAndroid Build Coastguard Worker elementCount = UnsignedCeilDivide(instanceCount, binding.getDivisor()); 558*8975f5c5SAndroid Build Coastguard Worker } 559*8975f5c5SAndroid Build Coastguard Worker size_t bytesIntendedToUse = (startElement + elementCount) * binding.getStride(); 560*8975f5c5SAndroid Build Coastguard Worker 561*8975f5c5SAndroid Build Coastguard Worker const mtl::VertexFormat &format = contextMtl->getVertexFormat(attrib.format->id, false); 562*8975f5c5SAndroid Build Coastguard Worker bool needStreaming = format.actualFormatId != format.intendedFormatId || 563*8975f5c5SAndroid Build Coastguard Worker (binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0 || 564*8975f5c5SAndroid Build Coastguard Worker (binding.getStride() < format.actualAngleFormat().pixelBytes) || 565*8975f5c5SAndroid Build Coastguard Worker bytesIntendedToUse > mInlineDataMaxSize; 566*8975f5c5SAndroid Build Coastguard Worker 567*8975f5c5SAndroid Build Coastguard Worker if (!needStreaming) 568*8975f5c5SAndroid Build Coastguard Worker { 569*8975f5c5SAndroid Build Coastguard Worker // Data will be uploaded directly as inline constant data 570*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBuffers[attribIndex] = nullptr; 571*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayInlineDataPointers[attribIndex] = src; 572*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayInlineDataSizes[attribIndex] = bytesIntendedToUse; 573*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferOffsets[attribIndex] = 0; 574*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferFormats[attribIndex] = &format; 575*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferStrides[attribIndex] = binding.getStride(); 576*8975f5c5SAndroid Build Coastguard Worker } 577*8975f5c5SAndroid Build Coastguard Worker else 578*8975f5c5SAndroid Build Coastguard Worker { 579*8975f5c5SAndroid Build Coastguard Worker GLuint convertedStride; 580*8975f5c5SAndroid Build Coastguard Worker // Need to stream the client vertex data to a buffer. 581*8975f5c5SAndroid Build Coastguard Worker const mtl::VertexFormat &streamFormat = 582*8975f5c5SAndroid Build Coastguard Worker GetVertexConversionFormat(contextMtl, attrib.format->id, &convertedStride); 583*8975f5c5SAndroid Build Coastguard Worker 584*8975f5c5SAndroid Build Coastguard Worker // Allocate space for startElement + elementCount so indexing will work. If we don't 585*8975f5c5SAndroid Build Coastguard Worker // start at zero all the indices will be off. 586*8975f5c5SAndroid Build Coastguard Worker // Only elementCount vertices will be used by the upcoming draw so that is all we copy. 587*8975f5c5SAndroid Build Coastguard Worker size_t bytesToAllocate = (startElement + elementCount) * convertedStride; 588*8975f5c5SAndroid Build Coastguard Worker src += startElement * binding.getStride(); 589*8975f5c5SAndroid Build Coastguard Worker size_t destOffset = startElement * convertedStride; 590*8975f5c5SAndroid Build Coastguard Worker 591*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferFormats[attribIndex] = &streamFormat; 592*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferStrides[attribIndex] = convertedStride; 593*8975f5c5SAndroid Build Coastguard Worker 594*8975f5c5SAndroid Build Coastguard Worker if (bytesToAllocate <= mInlineDataMaxSize) 595*8975f5c5SAndroid Build Coastguard Worker { 596*8975f5c5SAndroid Build Coastguard Worker // If the data is small enough, use host memory instead of creating GPU buffer. To 597*8975f5c5SAndroid Build Coastguard Worker // avoid synchronizing access to GPU buffer that is still in use. 598*8975f5c5SAndroid Build Coastguard Worker angle::MemoryBuffer &convertedClientArray = 599*8975f5c5SAndroid Build Coastguard Worker mConvertedClientSmallArrays[attribIndex]; 600*8975f5c5SAndroid Build Coastguard Worker if (bytesToAllocate > convertedClientArray.size()) 601*8975f5c5SAndroid Build Coastguard Worker { 602*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, convertedClientArray.resize(bytesToAllocate)); 603*8975f5c5SAndroid Build Coastguard Worker } 604*8975f5c5SAndroid Build Coastguard Worker 605*8975f5c5SAndroid Build Coastguard Worker ASSERT(streamFormat.vertexLoadFunction); 606*8975f5c5SAndroid Build Coastguard Worker streamFormat.vertexLoadFunction(src, binding.getStride(), elementCount, 607*8975f5c5SAndroid Build Coastguard Worker convertedClientArray.data() + destOffset); 608*8975f5c5SAndroid Build Coastguard Worker 609*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBuffers[attribIndex] = nullptr; 610*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayInlineDataPointers[attribIndex] = convertedClientArray.data(); 611*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayInlineDataSizes[attribIndex] = bytesToAllocate; 612*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferOffsets[attribIndex] = 0; 613*8975f5c5SAndroid Build Coastguard Worker } 614*8975f5c5SAndroid Build Coastguard Worker else 615*8975f5c5SAndroid Build Coastguard Worker { 616*8975f5c5SAndroid Build Coastguard Worker // Stream the client data to a GPU buffer. Synchronization might happen if buffer is 617*8975f5c5SAndroid Build Coastguard Worker // in use. 618*8975f5c5SAndroid Build Coastguard Worker mDynamicVertexData.updateAlignment(contextMtl, 619*8975f5c5SAndroid Build Coastguard Worker streamFormat.actualAngleFormat().pixelBytes); 620*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(StreamVertexData(contextMtl, &mDynamicVertexData, src, bytesToAllocate, 621*8975f5c5SAndroid Build Coastguard Worker destOffset, elementCount, binding.getStride(), 622*8975f5c5SAndroid Build Coastguard Worker streamFormat.vertexLoadFunction, 623*8975f5c5SAndroid Build Coastguard Worker &mConvertedArrayBufferHolders[attribIndex], 624*8975f5c5SAndroid Build Coastguard Worker &mCurrentArrayBufferOffsets[attribIndex])); 625*8975f5c5SAndroid Build Coastguard Worker if (contextMtl->getDisplay()->getFeatures().flushAfterStreamVertexData.enabled) 626*8975f5c5SAndroid Build Coastguard Worker { 627*8975f5c5SAndroid Build Coastguard Worker // WaitUntilScheduled is needed for this workaround. NoWait does not have the 628*8975f5c5SAndroid Build Coastguard Worker // needed effect. 629*8975f5c5SAndroid Build Coastguard Worker contextMtl->flushCommandBuffer(mtl::WaitUntilScheduled); 630*8975f5c5SAndroid Build Coastguard Worker } 631*8975f5c5SAndroid Build Coastguard Worker 632*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBuffers[attribIndex] = &mConvertedArrayBufferHolders[attribIndex]; 633*8975f5c5SAndroid Build Coastguard Worker } 634*8975f5c5SAndroid Build Coastguard Worker } // if (needStreaming) 635*8975f5c5SAndroid Build Coastguard Worker } 636*8975f5c5SAndroid Build Coastguard Worker 637*8975f5c5SAndroid Build Coastguard Worker mVertexArrayDirty = true; 638*8975f5c5SAndroid Build Coastguard Worker 639*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 640*8975f5c5SAndroid Build Coastguard Worker} 641*8975f5c5SAndroid Build Coastguard Worker 642*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::syncDirtyAttrib(const gl::Context *glContext, 643*8975f5c5SAndroid Build Coastguard Worker const gl::VertexAttribute &attrib, 644*8975f5c5SAndroid Build Coastguard Worker const gl::VertexBinding &binding, 645*8975f5c5SAndroid Build Coastguard Worker size_t attribIndex) 646*8975f5c5SAndroid Build Coastguard Worker{ 647*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(glContext); 648*8975f5c5SAndroid Build Coastguard Worker ASSERT(mtl::kMaxVertexAttribs > attribIndex); 649*8975f5c5SAndroid Build Coastguard Worker 650*8975f5c5SAndroid Build Coastguard Worker if (attrib.enabled) 651*8975f5c5SAndroid Build Coastguard Worker { 652*8975f5c5SAndroid Build Coastguard Worker gl::Buffer *bufferGL = binding.getBuffer().get(); 653*8975f5c5SAndroid Build Coastguard Worker const mtl::VertexFormat &format = contextMtl->getVertexFormat(attrib.format->id, false); 654*8975f5c5SAndroid Build Coastguard Worker 655*8975f5c5SAndroid Build Coastguard Worker if (bufferGL) 656*8975f5c5SAndroid Build Coastguard Worker { 657*8975f5c5SAndroid Build Coastguard Worker BufferMtl *bufferMtl = mtl::GetImpl(bufferGL); 658*8975f5c5SAndroid Build Coastguard Worker // https://bugs.webkit.org/show_bug.cgi?id=236733 659*8975f5c5SAndroid Build Coastguard Worker // even non-converted buffers need to be observed for potential 660*8975f5c5SAndroid Build Coastguard Worker // data rebinds. 661*8975f5c5SAndroid Build Coastguard Worker mContentsObservers->enableForBuffer(bufferGL, static_cast<uint32_t>(attribIndex)); 662*8975f5c5SAndroid Build Coastguard Worker bool needConversion = 663*8975f5c5SAndroid Build Coastguard Worker format.actualFormatId != format.intendedFormatId || 664*8975f5c5SAndroid Build Coastguard Worker (binding.getOffset() % mtl::kVertexAttribBufferStrideAlignment) != 0 || 665*8975f5c5SAndroid Build Coastguard Worker (binding.getStride() < format.actualAngleFormat().pixelBytes) || 666*8975f5c5SAndroid Build Coastguard Worker (binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0; 667*8975f5c5SAndroid Build Coastguard Worker 668*8975f5c5SAndroid Build Coastguard Worker if (needConversion) 669*8975f5c5SAndroid Build Coastguard Worker { 670*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(convertVertexBuffer(glContext, bufferMtl, binding, attribIndex, format)); 671*8975f5c5SAndroid Build Coastguard Worker } 672*8975f5c5SAndroid Build Coastguard Worker else 673*8975f5c5SAndroid Build Coastguard Worker { 674*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBuffers[attribIndex] = bufferMtl; 675*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferOffsets[attribIndex] = binding.getOffset(); 676*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferStrides[attribIndex] = binding.getStride(); 677*8975f5c5SAndroid Build Coastguard Worker 678*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferFormats[attribIndex] = &format; 679*8975f5c5SAndroid Build Coastguard Worker } 680*8975f5c5SAndroid Build Coastguard Worker } 681*8975f5c5SAndroid Build Coastguard Worker else 682*8975f5c5SAndroid Build Coastguard Worker { 683*8975f5c5SAndroid Build Coastguard Worker // ContextMtl must feed the client data using updateClientAttribs() 684*8975f5c5SAndroid Build Coastguard Worker } 685*8975f5c5SAndroid Build Coastguard Worker } 686*8975f5c5SAndroid Build Coastguard Worker else 687*8975f5c5SAndroid Build Coastguard Worker { 688*8975f5c5SAndroid Build Coastguard Worker // Use default attribute value. Handled in setupDraw(). 689*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBuffers[attribIndex] = nullptr; 690*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferOffsets[attribIndex] = 0; 691*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferStrides[attribIndex] = 0; 692*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferFormats[attribIndex] = 693*8975f5c5SAndroid Build Coastguard Worker &contextMtl->getVertexFormat(angle::FormatID::NONE, false); 694*8975f5c5SAndroid Build Coastguard Worker } 695*8975f5c5SAndroid Build Coastguard Worker 696*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 697*8975f5c5SAndroid Build Coastguard Worker} 698*8975f5c5SAndroid Build Coastguard Worker 699*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::getIndexBuffer(const gl::Context *context, 700*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType type, 701*8975f5c5SAndroid Build Coastguard Worker size_t count, 702*8975f5c5SAndroid Build Coastguard Worker const void *indices, 703*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef *idxBufferOut, 704*8975f5c5SAndroid Build Coastguard Worker size_t *idxBufferOffsetOut, 705*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType *indexTypeOut) 706*8975f5c5SAndroid Build Coastguard Worker{ 707*8975f5c5SAndroid Build Coastguard Worker const gl::Buffer *glElementArrayBuffer = getState().getElementArrayBuffer(); 708*8975f5c5SAndroid Build Coastguard Worker 709*8975f5c5SAndroid Build Coastguard Worker size_t convertedOffset = reinterpret_cast<size_t>(indices); 710*8975f5c5SAndroid Build Coastguard Worker if (!glElementArrayBuffer) 711*8975f5c5SAndroid Build Coastguard Worker { 712*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(streamIndexBufferFromClient(context, type, count, indices, idxBufferOut, 713*8975f5c5SAndroid Build Coastguard Worker idxBufferOffsetOut)); 714*8975f5c5SAndroid Build Coastguard Worker } 715*8975f5c5SAndroid Build Coastguard Worker else 716*8975f5c5SAndroid Build Coastguard Worker { 717*8975f5c5SAndroid Build Coastguard Worker bool needConversion = type == gl::DrawElementsType::UnsignedByte; 718*8975f5c5SAndroid Build Coastguard Worker if (needConversion) 719*8975f5c5SAndroid Build Coastguard Worker { 720*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(convertIndexBuffer(context, type, convertedOffset, idxBufferOut, 721*8975f5c5SAndroid Build Coastguard Worker idxBufferOffsetOut)); 722*8975f5c5SAndroid Build Coastguard Worker } 723*8975f5c5SAndroid Build Coastguard Worker else 724*8975f5c5SAndroid Build Coastguard Worker { 725*8975f5c5SAndroid Build Coastguard Worker // No conversion needed: 726*8975f5c5SAndroid Build Coastguard Worker BufferMtl *bufferMtl = mtl::GetImpl(glElementArrayBuffer); 727*8975f5c5SAndroid Build Coastguard Worker *idxBufferOut = bufferMtl->getCurrentBuffer(); 728*8975f5c5SAndroid Build Coastguard Worker *idxBufferOffsetOut = convertedOffset; 729*8975f5c5SAndroid Build Coastguard Worker } 730*8975f5c5SAndroid Build Coastguard Worker } 731*8975f5c5SAndroid Build Coastguard Worker 732*8975f5c5SAndroid Build Coastguard Worker *indexTypeOut = type; 733*8975f5c5SAndroid Build Coastguard Worker if (type == gl::DrawElementsType::UnsignedByte) 734*8975f5c5SAndroid Build Coastguard Worker { 735*8975f5c5SAndroid Build Coastguard Worker // This buffer is already converted to ushort indices above 736*8975f5c5SAndroid Build Coastguard Worker *indexTypeOut = gl::DrawElementsType::UnsignedShort; 737*8975f5c5SAndroid Build Coastguard Worker } 738*8975f5c5SAndroid Build Coastguard Worker 739*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 740*8975f5c5SAndroid Build Coastguard Worker} 741*8975f5c5SAndroid Build Coastguard Worker 742*8975f5c5SAndroid Build Coastguard Workerstd::vector<DrawCommandRange> VertexArrayMtl::getDrawIndices(const gl::Context *glContext, 743*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType originalIndexType, 744*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType indexType, 745*8975f5c5SAndroid Build Coastguard Worker gl::PrimitiveMode primitiveMode, 746*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef clientBuffer, 747*8975f5c5SAndroid Build Coastguard Worker uint32_t indexCount, 748*8975f5c5SAndroid Build Coastguard Worker size_t offset) 749*8975f5c5SAndroid Build Coastguard Worker{ 750*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(glContext); 751*8975f5c5SAndroid Build Coastguard Worker std::vector<DrawCommandRange> drawCommands; 752*8975f5c5SAndroid Build Coastguard Worker // The indexed draw needs to be split to separate draw commands in case primitive restart is 753*8975f5c5SAndroid Build Coastguard Worker // enabled and the drawn primitive supports primitive restart. Otherwise the whole indexed draw 754*8975f5c5SAndroid Build Coastguard Worker // can be sent as one draw command. 755*8975f5c5SAndroid Build Coastguard Worker bool isSimpleType = primitiveMode == gl::PrimitiveMode::Points || 756*8975f5c5SAndroid Build Coastguard Worker primitiveMode == gl::PrimitiveMode::Lines || 757*8975f5c5SAndroid Build Coastguard Worker primitiveMode == gl::PrimitiveMode::Triangles; 758*8975f5c5SAndroid Build Coastguard Worker if (!isSimpleType || !glContext->getState().isPrimitiveRestartEnabled()) 759*8975f5c5SAndroid Build Coastguard Worker { 760*8975f5c5SAndroid Build Coastguard Worker drawCommands.push_back({indexCount, offset}); 761*8975f5c5SAndroid Build Coastguard Worker return drawCommands; 762*8975f5c5SAndroid Build Coastguard Worker } 763*8975f5c5SAndroid Build Coastguard Worker const std::vector<IndexRange> *restartIndices; 764*8975f5c5SAndroid Build Coastguard Worker std::vector<IndexRange> clientIndexRange; 765*8975f5c5SAndroid Build Coastguard Worker const gl::Buffer *glElementArrayBuffer = getState().getElementArrayBuffer(); 766*8975f5c5SAndroid Build Coastguard Worker if (glElementArrayBuffer) 767*8975f5c5SAndroid Build Coastguard Worker { 768*8975f5c5SAndroid Build Coastguard Worker BufferMtl *idxBuffer = mtl::GetImpl(glElementArrayBuffer); 769*8975f5c5SAndroid Build Coastguard Worker restartIndices = &idxBuffer->getRestartIndices(contextMtl, originalIndexType); 770*8975f5c5SAndroid Build Coastguard Worker } 771*8975f5c5SAndroid Build Coastguard Worker else 772*8975f5c5SAndroid Build Coastguard Worker { 773*8975f5c5SAndroid Build Coastguard Worker clientIndexRange = 774*8975f5c5SAndroid Build Coastguard Worker BufferMtl::getRestartIndicesFromClientData(contextMtl, indexType, clientBuffer); 775*8975f5c5SAndroid Build Coastguard Worker restartIndices = &clientIndexRange; 776*8975f5c5SAndroid Build Coastguard Worker } 777*8975f5c5SAndroid Build Coastguard Worker // Reminder, offset is in bytes, not elements. 778*8975f5c5SAndroid Build Coastguard Worker // Slice draw commands based off of indices. 779*8975f5c5SAndroid Build Coastguard Worker uint32_t nIndicesPerPrimitive; 780*8975f5c5SAndroid Build Coastguard Worker switch (primitiveMode) 781*8975f5c5SAndroid Build Coastguard Worker { 782*8975f5c5SAndroid Build Coastguard Worker case gl::PrimitiveMode::Points: 783*8975f5c5SAndroid Build Coastguard Worker nIndicesPerPrimitive = 1; 784*8975f5c5SAndroid Build Coastguard Worker break; 785*8975f5c5SAndroid Build Coastguard Worker case gl::PrimitiveMode::Lines: 786*8975f5c5SAndroid Build Coastguard Worker nIndicesPerPrimitive = 2; 787*8975f5c5SAndroid Build Coastguard Worker break; 788*8975f5c5SAndroid Build Coastguard Worker case gl::PrimitiveMode::Triangles: 789*8975f5c5SAndroid Build Coastguard Worker nIndicesPerPrimitive = 3; 790*8975f5c5SAndroid Build Coastguard Worker break; 791*8975f5c5SAndroid Build Coastguard Worker default: 792*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 793*8975f5c5SAndroid Build Coastguard Worker return drawCommands; 794*8975f5c5SAndroid Build Coastguard Worker } 795*8975f5c5SAndroid Build Coastguard Worker const GLuint indexTypeBytes = gl::GetDrawElementsTypeSize(indexType); 796*8975f5c5SAndroid Build Coastguard Worker uint32_t indicesLeft = indexCount; 797*8975f5c5SAndroid Build Coastguard Worker size_t currentIndexOffset = offset / indexTypeBytes; 798*8975f5c5SAndroid Build Coastguard Worker 799*8975f5c5SAndroid Build Coastguard Worker for (auto &range : *restartIndices) 800*8975f5c5SAndroid Build Coastguard Worker { 801*8975f5c5SAndroid Build Coastguard Worker if (range.restartBegin > currentIndexOffset) 802*8975f5c5SAndroid Build Coastguard Worker { 803*8975f5c5SAndroid Build Coastguard Worker int64_t nIndicesInSlice = 804*8975f5c5SAndroid Build Coastguard Worker MIN(((int64_t)range.restartBegin - currentIndexOffset) - 805*8975f5c5SAndroid Build Coastguard Worker ((int64_t)range.restartBegin - currentIndexOffset) % nIndicesPerPrimitive, 806*8975f5c5SAndroid Build Coastguard Worker indicesLeft); 807*8975f5c5SAndroid Build Coastguard Worker size_t restartSize = (range.restartEnd - range.restartBegin) + 1; 808*8975f5c5SAndroid Build Coastguard Worker if (nIndicesInSlice >= nIndicesPerPrimitive) 809*8975f5c5SAndroid Build Coastguard Worker { 810*8975f5c5SAndroid Build Coastguard Worker drawCommands.push_back( 811*8975f5c5SAndroid Build Coastguard Worker {(uint32_t)nIndicesInSlice, currentIndexOffset * indexTypeBytes}); 812*8975f5c5SAndroid Build Coastguard Worker } 813*8975f5c5SAndroid Build Coastguard Worker // Account for dropped indices due to incomplete primitives. 814*8975f5c5SAndroid Build Coastguard Worker size_t indicesUsed = ((range.restartBegin + restartSize) - currentIndexOffset); 815*8975f5c5SAndroid Build Coastguard Worker if (indicesLeft <= indicesUsed) 816*8975f5c5SAndroid Build Coastguard Worker { 817*8975f5c5SAndroid Build Coastguard Worker indicesLeft = 0; 818*8975f5c5SAndroid Build Coastguard Worker } 819*8975f5c5SAndroid Build Coastguard Worker else 820*8975f5c5SAndroid Build Coastguard Worker { 821*8975f5c5SAndroid Build Coastguard Worker indicesLeft -= indicesUsed; 822*8975f5c5SAndroid Build Coastguard Worker } 823*8975f5c5SAndroid Build Coastguard Worker currentIndexOffset = (size_t)(range.restartBegin + restartSize); 824*8975f5c5SAndroid Build Coastguard Worker } 825*8975f5c5SAndroid Build Coastguard Worker // If the initial offset into the index buffer is within a restart zone, move to the end of 826*8975f5c5SAndroid Build Coastguard Worker // the restart zone. 827*8975f5c5SAndroid Build Coastguard Worker else if (range.restartEnd >= currentIndexOffset) 828*8975f5c5SAndroid Build Coastguard Worker { 829*8975f5c5SAndroid Build Coastguard Worker size_t restartSize = (range.restartEnd - currentIndexOffset) + 1; 830*8975f5c5SAndroid Build Coastguard Worker if (indicesLeft <= restartSize) 831*8975f5c5SAndroid Build Coastguard Worker { 832*8975f5c5SAndroid Build Coastguard Worker indicesLeft = 0; 833*8975f5c5SAndroid Build Coastguard Worker } 834*8975f5c5SAndroid Build Coastguard Worker else 835*8975f5c5SAndroid Build Coastguard Worker { 836*8975f5c5SAndroid Build Coastguard Worker indicesLeft -= restartSize; 837*8975f5c5SAndroid Build Coastguard Worker } 838*8975f5c5SAndroid Build Coastguard Worker currentIndexOffset = (size_t)(currentIndexOffset + restartSize); 839*8975f5c5SAndroid Build Coastguard Worker } 840*8975f5c5SAndroid Build Coastguard Worker } 841*8975f5c5SAndroid Build Coastguard Worker if (indicesLeft >= nIndicesPerPrimitive) 842*8975f5c5SAndroid Build Coastguard Worker drawCommands.push_back({indicesLeft, currentIndexOffset * indexTypeBytes}); 843*8975f5c5SAndroid Build Coastguard Worker return drawCommands; 844*8975f5c5SAndroid Build Coastguard Worker} 845*8975f5c5SAndroid Build Coastguard Worker 846*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::convertIndexBuffer(const gl::Context *glContext, 847*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType indexType, 848*8975f5c5SAndroid Build Coastguard Worker size_t offset, 849*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef *idxBufferOut, 850*8975f5c5SAndroid Build Coastguard Worker size_t *idxBufferOffsetOut) 851*8975f5c5SAndroid Build Coastguard Worker{ 852*8975f5c5SAndroid Build Coastguard Worker size_t offsetModulo = offset % mtl::kIndexBufferOffsetAlignment; 853*8975f5c5SAndroid Build Coastguard Worker ASSERT(offsetModulo != 0 || indexType == gl::DrawElementsType::UnsignedByte); 854*8975f5c5SAndroid Build Coastguard Worker 855*8975f5c5SAndroid Build Coastguard Worker size_t alignedOffset = offset - offsetModulo; 856*8975f5c5SAndroid Build Coastguard Worker if (indexType == gl::DrawElementsType::UnsignedByte) 857*8975f5c5SAndroid Build Coastguard Worker { 858*8975f5c5SAndroid Build Coastguard Worker // Unsigned byte index will be promoted to unsigned short, thus double its offset. 859*8975f5c5SAndroid Build Coastguard Worker alignedOffset = alignedOffset << 1; 860*8975f5c5SAndroid Build Coastguard Worker } 861*8975f5c5SAndroid Build Coastguard Worker 862*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(glContext); 863*8975f5c5SAndroid Build Coastguard Worker const gl::State &glState = glContext->getState(); 864*8975f5c5SAndroid Build Coastguard Worker BufferMtl *idxBuffer = mtl::GetImpl(getState().getElementArrayBuffer()); 865*8975f5c5SAndroid Build Coastguard Worker 866*8975f5c5SAndroid Build Coastguard Worker IndexConversionBufferMtl *conversion = idxBuffer->getIndexConversionBuffer( 867*8975f5c5SAndroid Build Coastguard Worker contextMtl, indexType, glState.isPrimitiveRestartEnabled(), offsetModulo); 868*8975f5c5SAndroid Build Coastguard Worker 869*8975f5c5SAndroid Build Coastguard Worker // Has the content of the buffer has changed since last conversion? 870*8975f5c5SAndroid Build Coastguard Worker if (!conversion->dirty) 871*8975f5c5SAndroid Build Coastguard Worker { 872*8975f5c5SAndroid Build Coastguard Worker // reuse the converted buffer 873*8975f5c5SAndroid Build Coastguard Worker *idxBufferOut = conversion->convertedBuffer; 874*8975f5c5SAndroid Build Coastguard Worker *idxBufferOffsetOut = conversion->convertedOffset + alignedOffset; 875*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 876*8975f5c5SAndroid Build Coastguard Worker } 877*8975f5c5SAndroid Build Coastguard Worker 878*8975f5c5SAndroid Build Coastguard Worker size_t indexCount = GetIndexCount(idxBuffer, offsetModulo, indexType); 879*8975f5c5SAndroid Build Coastguard Worker if ((!contextMtl->getDisplay()->getFeatures().hasCheapRenderPass.enabled && 880*8975f5c5SAndroid Build Coastguard Worker contextMtl->getRenderCommandEncoder())) 881*8975f5c5SAndroid Build Coastguard Worker { 882*8975f5c5SAndroid Build Coastguard Worker // We shouldn't use GPU to convert when we are in a middle of a render pass. 883*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(StreamIndexData(contextMtl, &conversion->data, 884*8975f5c5SAndroid Build Coastguard Worker idxBuffer->getBufferDataReadOnly(contextMtl) + offsetModulo, 885*8975f5c5SAndroid Build Coastguard Worker indexType, indexCount, glState.isPrimitiveRestartEnabled(), 886*8975f5c5SAndroid Build Coastguard Worker &conversion->convertedBuffer, &conversion->convertedOffset)); 887*8975f5c5SAndroid Build Coastguard Worker } 888*8975f5c5SAndroid Build Coastguard Worker else 889*8975f5c5SAndroid Build Coastguard Worker { 890*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(convertIndexBufferGPU(glContext, indexType, idxBuffer, offsetModulo, indexCount, 891*8975f5c5SAndroid Build Coastguard Worker conversion)); 892*8975f5c5SAndroid Build Coastguard Worker } 893*8975f5c5SAndroid Build Coastguard Worker // Calculate ranges for prim restart simple types. 894*8975f5c5SAndroid Build Coastguard Worker *idxBufferOut = conversion->convertedBuffer; 895*8975f5c5SAndroid Build Coastguard Worker *idxBufferOffsetOut = conversion->convertedOffset + alignedOffset; 896*8975f5c5SAndroid Build Coastguard Worker 897*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 898*8975f5c5SAndroid Build Coastguard Worker} 899*8975f5c5SAndroid Build Coastguard Worker 900*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::convertIndexBufferGPU(const gl::Context *glContext, 901*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType indexType, 902*8975f5c5SAndroid Build Coastguard Worker BufferMtl *idxBuffer, 903*8975f5c5SAndroid Build Coastguard Worker size_t offset, 904*8975f5c5SAndroid Build Coastguard Worker size_t indexCount, 905*8975f5c5SAndroid Build Coastguard Worker IndexConversionBufferMtl *conversion) 906*8975f5c5SAndroid Build Coastguard Worker{ 907*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(glContext); 908*8975f5c5SAndroid Build Coastguard Worker DisplayMtl *display = contextMtl->getDisplay(); 909*8975f5c5SAndroid Build Coastguard Worker 910*8975f5c5SAndroid Build Coastguard Worker const size_t amount = GetIndexConvertedBufferSize(indexType, indexCount); 911*8975f5c5SAndroid Build Coastguard Worker 912*8975f5c5SAndroid Build Coastguard Worker // Allocate new buffer, save it in conversion struct so that we can reuse it when the content 913*8975f5c5SAndroid Build Coastguard Worker // of the original buffer is not dirty. 914*8975f5c5SAndroid Build Coastguard Worker conversion->data.releaseInFlightBuffers(contextMtl); 915*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(conversion->data.allocate(contextMtl, amount, nullptr, &conversion->convertedBuffer, 916*8975f5c5SAndroid Build Coastguard Worker &conversion->convertedOffset)); 917*8975f5c5SAndroid Build Coastguard Worker 918*8975f5c5SAndroid Build Coastguard Worker // Do the conversion on GPU. 919*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(display->getUtils().convertIndexBufferGPU( 920*8975f5c5SAndroid Build Coastguard Worker contextMtl, {indexType, static_cast<uint32_t>(indexCount), idxBuffer->getCurrentBuffer(), 921*8975f5c5SAndroid Build Coastguard Worker static_cast<uint32_t>(offset), conversion->convertedBuffer, 922*8975f5c5SAndroid Build Coastguard Worker static_cast<uint32_t>(conversion->convertedOffset), 923*8975f5c5SAndroid Build Coastguard Worker glContext->getState().isPrimitiveRestartEnabled()})); 924*8975f5c5SAndroid Build Coastguard Worker 925*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(conversion->data.commit(contextMtl)); 926*8975f5c5SAndroid Build Coastguard Worker 927*8975f5c5SAndroid Build Coastguard Worker ASSERT(conversion->dirty); 928*8975f5c5SAndroid Build Coastguard Worker conversion->dirty = false; 929*8975f5c5SAndroid Build Coastguard Worker 930*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 931*8975f5c5SAndroid Build Coastguard Worker} 932*8975f5c5SAndroid Build Coastguard Worker 933*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::streamIndexBufferFromClient(const gl::Context *context, 934*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType indexType, 935*8975f5c5SAndroid Build Coastguard Worker size_t indexCount, 936*8975f5c5SAndroid Build Coastguard Worker const void *sourcePointer, 937*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef *idxBufferOut, 938*8975f5c5SAndroid Build Coastguard Worker size_t *idxBufferOffsetOut) 939*8975f5c5SAndroid Build Coastguard Worker{ 940*8975f5c5SAndroid Build Coastguard Worker ASSERT(getState().getElementArrayBuffer() == nullptr); 941*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 942*8975f5c5SAndroid Build Coastguard Worker 943*8975f5c5SAndroid Build Coastguard Worker auto srcData = static_cast<const uint8_t *>(sourcePointer); 944*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(StreamIndexData(contextMtl, &mDynamicIndexData, srcData, indexType, indexCount, 945*8975f5c5SAndroid Build Coastguard Worker context->getState().isPrimitiveRestartEnabled(), idxBufferOut, 946*8975f5c5SAndroid Build Coastguard Worker idxBufferOffsetOut)); 947*8975f5c5SAndroid Build Coastguard Worker 948*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 949*8975f5c5SAndroid Build Coastguard Worker} 950*8975f5c5SAndroid Build Coastguard Worker 951*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext, 952*8975f5c5SAndroid Build Coastguard Worker BufferMtl *srcBuffer, 953*8975f5c5SAndroid Build Coastguard Worker const gl::VertexBinding &binding, 954*8975f5c5SAndroid Build Coastguard Worker size_t attribIndex, 955*8975f5c5SAndroid Build Coastguard Worker const mtl::VertexFormat &srcVertexFormat) 956*8975f5c5SAndroid Build Coastguard Worker{ 957*8975f5c5SAndroid Build Coastguard Worker unsigned srcFormatSize = srcVertexFormat.intendedAngleFormat().pixelBytes; 958*8975f5c5SAndroid Build Coastguard Worker 959*8975f5c5SAndroid Build Coastguard Worker size_t numVertices = GetVertexCount(srcBuffer, binding, srcFormatSize); 960*8975f5c5SAndroid Build Coastguard Worker if (numVertices == 0) 961*8975f5c5SAndroid Build Coastguard Worker { 962*8975f5c5SAndroid Build Coastguard Worker // Out of bound buffer access, can return any values. 963*8975f5c5SAndroid Build Coastguard Worker // See KHR_robust_buffer_access_behavior 964*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBuffers[attribIndex] = srcBuffer; 965*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferFormats[attribIndex] = &srcVertexFormat; 966*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferOffsets[attribIndex] = 0; 967*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferStrides[attribIndex] = 16; 968*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 969*8975f5c5SAndroid Build Coastguard Worker } 970*8975f5c5SAndroid Build Coastguard Worker 971*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(glContext); 972*8975f5c5SAndroid Build Coastguard Worker 973*8975f5c5SAndroid Build Coastguard Worker // Convert to tightly packed format 974*8975f5c5SAndroid Build Coastguard Worker GLuint stride; 975*8975f5c5SAndroid Build Coastguard Worker const mtl::VertexFormat &convertedFormat = 976*8975f5c5SAndroid Build Coastguard Worker GetVertexConversionFormat(contextMtl, srcVertexFormat.intendedFormatId, &stride); 977*8975f5c5SAndroid Build Coastguard Worker 978*8975f5c5SAndroid Build Coastguard Worker ConversionBufferMtl *conversion = srcBuffer->getVertexConversionBuffer( 979*8975f5c5SAndroid Build Coastguard Worker contextMtl, srcVertexFormat.intendedFormatId, binding.getStride(), binding.getOffset()); 980*8975f5c5SAndroid Build Coastguard Worker 981*8975f5c5SAndroid Build Coastguard Worker // Has the content of the buffer has changed since last conversion? 982*8975f5c5SAndroid Build Coastguard Worker if (!conversion->dirty) 983*8975f5c5SAndroid Build Coastguard Worker { 984*8975f5c5SAndroid Build Coastguard Worker VertexConversionBufferMtl *vertexConversionMtl = 985*8975f5c5SAndroid Build Coastguard Worker static_cast<VertexConversionBufferMtl *>(conversion); 986*8975f5c5SAndroid Build Coastguard Worker ASSERT((binding.getOffset() - vertexConversionMtl->offset) % binding.getStride() == 0); 987*8975f5c5SAndroid Build Coastguard Worker mConvertedArrayBufferHolders[attribIndex].set(conversion->convertedBuffer); 988*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferOffsets[attribIndex] = 989*8975f5c5SAndroid Build Coastguard Worker conversion->convertedOffset + 990*8975f5c5SAndroid Build Coastguard Worker stride * ((binding.getOffset() - vertexConversionMtl->offset) / binding.getStride()); 991*8975f5c5SAndroid Build Coastguard Worker 992*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBuffers[attribIndex] = &mConvertedArrayBufferHolders[attribIndex]; 993*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferFormats[attribIndex] = &convertedFormat; 994*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferStrides[attribIndex] = stride; 995*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 996*8975f5c5SAndroid Build Coastguard Worker } 997*8975f5c5SAndroid Build Coastguard Worker numVertices = GetVertexCountWithConversion( 998*8975f5c5SAndroid Build Coastguard Worker srcBuffer, static_cast<VertexConversionBufferMtl *>(conversion), binding, srcFormatSize); 999*8975f5c5SAndroid Build Coastguard Worker 1000*8975f5c5SAndroid Build Coastguard Worker const angle::Format &convertedAngleFormat = convertedFormat.actualAngleFormat(); 1001*8975f5c5SAndroid Build Coastguard Worker bool canConvertToFloatOnGPU = 1002*8975f5c5SAndroid Build Coastguard Worker convertedAngleFormat.isFloat() && !convertedAngleFormat.isVertexTypeHalfFloat(); 1003*8975f5c5SAndroid Build Coastguard Worker 1004*8975f5c5SAndroid Build Coastguard Worker bool canExpandComponentsOnGPU = convertedFormat.actualSameGLType; 1005*8975f5c5SAndroid Build Coastguard Worker 1006*8975f5c5SAndroid Build Coastguard Worker conversion->data.releaseInFlightBuffers(contextMtl); 1007*8975f5c5SAndroid Build Coastguard Worker conversion->data.updateAlignment(contextMtl, convertedAngleFormat.pixelBytes); 1008*8975f5c5SAndroid Build Coastguard Worker 1009*8975f5c5SAndroid Build Coastguard Worker if (canConvertToFloatOnGPU || canExpandComponentsOnGPU) 1010*8975f5c5SAndroid Build Coastguard Worker { 1011*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(convertVertexBufferGPU(glContext, srcBuffer, binding, attribIndex, 1012*8975f5c5SAndroid Build Coastguard Worker convertedFormat, stride, numVertices, 1013*8975f5c5SAndroid Build Coastguard Worker canExpandComponentsOnGPU, conversion)); 1014*8975f5c5SAndroid Build Coastguard Worker } 1015*8975f5c5SAndroid Build Coastguard Worker else 1016*8975f5c5SAndroid Build Coastguard Worker { 1017*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(convertVertexBufferCPU(contextMtl, srcBuffer, binding, attribIndex, 1018*8975f5c5SAndroid Build Coastguard Worker convertedFormat, stride, numVertices, conversion)); 1019*8975f5c5SAndroid Build Coastguard Worker } 1020*8975f5c5SAndroid Build Coastguard Worker 1021*8975f5c5SAndroid Build Coastguard Worker mConvertedArrayBufferHolders[attribIndex].set(conversion->convertedBuffer); 1022*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferOffsets[attribIndex] = 1023*8975f5c5SAndroid Build Coastguard Worker conversion->convertedOffset + 1024*8975f5c5SAndroid Build Coastguard Worker stride * 1025*8975f5c5SAndroid Build Coastguard Worker ((binding.getOffset() - static_cast<VertexConversionBufferMtl *>(conversion)->offset) / 1026*8975f5c5SAndroid Build Coastguard Worker binding.getStride()); 1027*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBuffers[attribIndex] = &mConvertedArrayBufferHolders[attribIndex]; 1028*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferFormats[attribIndex] = &convertedFormat; 1029*8975f5c5SAndroid Build Coastguard Worker mCurrentArrayBufferStrides[attribIndex] = stride; 1030*8975f5c5SAndroid Build Coastguard Worker 1031*8975f5c5SAndroid Build Coastguard Worker ASSERT(conversion->dirty); 1032*8975f5c5SAndroid Build Coastguard Worker conversion->dirty = false; 1033*8975f5c5SAndroid Build Coastguard Worker 1034*8975f5c5SAndroid Build Coastguard Worker#ifndef NDEBUG 1035*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_OBJC_SCOPE 1036*8975f5c5SAndroid Build Coastguard Worker { 1037*8975f5c5SAndroid Build Coastguard Worker mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer()->get().label = 1038*8975f5c5SAndroid Build Coastguard Worker [NSString stringWithFormat:@"Converted from %p offset=%zu stride=%u", srcBuffer, 1039*8975f5c5SAndroid Build Coastguard Worker binding.getOffset(), binding.getStride()]; 1040*8975f5c5SAndroid Build Coastguard Worker } 1041*8975f5c5SAndroid Build Coastguard Worker#endif 1042*8975f5c5SAndroid Build Coastguard Worker 1043*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1044*8975f5c5SAndroid Build Coastguard Worker} 1045*8975f5c5SAndroid Build Coastguard Worker 1046*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::convertVertexBufferCPU(ContextMtl *contextMtl, 1047*8975f5c5SAndroid Build Coastguard Worker BufferMtl *srcBuffer, 1048*8975f5c5SAndroid Build Coastguard Worker const gl::VertexBinding &binding, 1049*8975f5c5SAndroid Build Coastguard Worker size_t attribIndex, 1050*8975f5c5SAndroid Build Coastguard Worker const mtl::VertexFormat &convertedFormat, 1051*8975f5c5SAndroid Build Coastguard Worker GLuint targetStride, 1052*8975f5c5SAndroid Build Coastguard Worker size_t numVertices, 1053*8975f5c5SAndroid Build Coastguard Worker ConversionBufferMtl *conversion) 1054*8975f5c5SAndroid Build Coastguard Worker{ 1055*8975f5c5SAndroid Build Coastguard Worker 1056*8975f5c5SAndroid Build Coastguard Worker const uint8_t *srcBytes = srcBuffer->getBufferDataReadOnly(contextMtl); 1057*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_ALLOC(contextMtl, srcBytes); 1058*8975f5c5SAndroid Build Coastguard Worker VertexConversionBufferMtl *vertexConverison = 1059*8975f5c5SAndroid Build Coastguard Worker static_cast<VertexConversionBufferMtl *>(conversion); 1060*8975f5c5SAndroid Build Coastguard Worker srcBytes += MIN(binding.getOffset(), static_cast<GLintptr>(vertexConverison->offset)); 1061*8975f5c5SAndroid Build Coastguard Worker SimpleWeakBufferHolderMtl conversionBufferHolder; 1062*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(StreamVertexData(contextMtl, &conversion->data, srcBytes, numVertices * targetStride, 1063*8975f5c5SAndroid Build Coastguard Worker 0, numVertices, binding.getStride(), 1064*8975f5c5SAndroid Build Coastguard Worker convertedFormat.vertexLoadFunction, &conversionBufferHolder, 1065*8975f5c5SAndroid Build Coastguard Worker &conversion->convertedOffset)); 1066*8975f5c5SAndroid Build Coastguard Worker conversion->convertedBuffer = conversionBufferHolder.getCurrentBuffer(); 1067*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1068*8975f5c5SAndroid Build Coastguard Worker} 1069*8975f5c5SAndroid Build Coastguard Worker 1070*8975f5c5SAndroid Build Coastguard Workerangle::Result VertexArrayMtl::convertVertexBufferGPU(const gl::Context *glContext, 1071*8975f5c5SAndroid Build Coastguard Worker BufferMtl *srcBuffer, 1072*8975f5c5SAndroid Build Coastguard Worker const gl::VertexBinding &binding, 1073*8975f5c5SAndroid Build Coastguard Worker size_t attribIndex, 1074*8975f5c5SAndroid Build Coastguard Worker const mtl::VertexFormat &convertedFormat, 1075*8975f5c5SAndroid Build Coastguard Worker GLuint targetStride, 1076*8975f5c5SAndroid Build Coastguard Worker size_t numVertices, 1077*8975f5c5SAndroid Build Coastguard Worker bool isExpandingComponents, 1078*8975f5c5SAndroid Build Coastguard Worker ConversionBufferMtl *conversion) 1079*8975f5c5SAndroid Build Coastguard Worker{ 1080*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(glContext); 1081*8975f5c5SAndroid Build Coastguard Worker 1082*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef newBuffer; 1083*8975f5c5SAndroid Build Coastguard Worker size_t newBufferOffset; 1084*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(conversion->data.allocate(contextMtl, numVertices * targetStride, nullptr, &newBuffer, 1085*8975f5c5SAndroid Build Coastguard Worker &newBufferOffset)); 1086*8975f5c5SAndroid Build Coastguard Worker 1087*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_MATH(contextMtl, binding.getOffset() <= std::numeric_limits<uint32_t>::max()); 1088*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_MATH(contextMtl, newBufferOffset <= std::numeric_limits<uint32_t>::max()); 1089*8975f5c5SAndroid Build Coastguard Worker ANGLE_CHECK_GL_MATH(contextMtl, numVertices <= std::numeric_limits<uint32_t>::max()); 1090*8975f5c5SAndroid Build Coastguard Worker 1091*8975f5c5SAndroid Build Coastguard Worker mtl::VertexFormatConvertParams params; 1092*8975f5c5SAndroid Build Coastguard Worker VertexConversionBufferMtl *vertexConversion = 1093*8975f5c5SAndroid Build Coastguard Worker static_cast<VertexConversionBufferMtl *>(conversion); 1094*8975f5c5SAndroid Build Coastguard Worker params.srcBuffer = srcBuffer->getCurrentBuffer(); 1095*8975f5c5SAndroid Build Coastguard Worker params.srcBufferStartOffset = static_cast<uint32_t>( 1096*8975f5c5SAndroid Build Coastguard Worker MIN(static_cast<GLintptr>(vertexConversion->offset), binding.getOffset())); 1097*8975f5c5SAndroid Build Coastguard Worker params.srcStride = binding.getStride(); 1098*8975f5c5SAndroid Build Coastguard Worker params.srcDefaultAlphaData = convertedFormat.defaultAlpha; 1099*8975f5c5SAndroid Build Coastguard Worker 1100*8975f5c5SAndroid Build Coastguard Worker params.dstBuffer = newBuffer; 1101*8975f5c5SAndroid Build Coastguard Worker params.dstBufferStartOffset = static_cast<uint32_t>(newBufferOffset); 1102*8975f5c5SAndroid Build Coastguard Worker params.dstStride = targetStride; 1103*8975f5c5SAndroid Build Coastguard Worker params.dstComponents = convertedFormat.actualAngleFormat().channelCount; 1104*8975f5c5SAndroid Build Coastguard Worker 1105*8975f5c5SAndroid Build Coastguard Worker params.vertexCount = static_cast<uint32_t>(numVertices); 1106*8975f5c5SAndroid Build Coastguard Worker 1107*8975f5c5SAndroid Build Coastguard Worker mtl::RenderUtils &utils = contextMtl->getDisplay()->getUtils(); 1108*8975f5c5SAndroid Build Coastguard Worker 1109*8975f5c5SAndroid Build Coastguard Worker // Compute based buffer conversion. 1110*8975f5c5SAndroid Build Coastguard Worker if (!isExpandingComponents) 1111*8975f5c5SAndroid Build Coastguard Worker { 1112*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(utils.convertVertexFormatToFloatCS( 1113*8975f5c5SAndroid Build Coastguard Worker contextMtl, convertedFormat.intendedAngleFormat(), params)); 1114*8975f5c5SAndroid Build Coastguard Worker } 1115*8975f5c5SAndroid Build Coastguard Worker else 1116*8975f5c5SAndroid Build Coastguard Worker { 1117*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(utils.expandVertexFormatComponentsCS( 1118*8975f5c5SAndroid Build Coastguard Worker contextMtl, convertedFormat.intendedAngleFormat(), params)); 1119*8975f5c5SAndroid Build Coastguard Worker } 1120*8975f5c5SAndroid Build Coastguard Worker 1121*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(conversion->data.commit(contextMtl)); 1122*8975f5c5SAndroid Build Coastguard Worker 1123*8975f5c5SAndroid Build Coastguard Worker conversion->convertedBuffer = newBuffer; 1124*8975f5c5SAndroid Build Coastguard Worker conversion->convertedOffset = newBufferOffset; 1125*8975f5c5SAndroid Build Coastguard Worker 1126*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 1127*8975f5c5SAndroid Build Coastguard Worker} 1128*8975f5c5SAndroid Build Coastguard Worker} // namespace rx 1129