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// BufferMtl.mm: 7*8975f5c5SAndroid Build Coastguard Worker// Implements the class methods for BufferMtl. 8*8975f5c5SAndroid Build Coastguard Worker// 9*8975f5c5SAndroid Build Coastguard Worker 10*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/BufferMtl.h" 11*8975f5c5SAndroid Build Coastguard Worker 12*8975f5c5SAndroid Build Coastguard Worker#include "common/debug.h" 13*8975f5c5SAndroid Build Coastguard Worker#include "common/utilities.h" 14*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ContextMtl.h" 15*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/DisplayMtl.h" 16*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/mtl_buffer_manager.h" 17*8975f5c5SAndroid Build Coastguard Worker 18*8975f5c5SAndroid Build Coastguard Workernamespace rx 19*8975f5c5SAndroid Build Coastguard Worker{ 20*8975f5c5SAndroid Build Coastguard Worker 21*8975f5c5SAndroid Build Coastguard Workernamespace 22*8975f5c5SAndroid Build Coastguard Worker{ 23*8975f5c5SAndroid Build Coastguard Worker 24*8975f5c5SAndroid Build Coastguard Worker// Start with a fairly small buffer size. We can increase this dynamically as we convert more data. 25*8975f5c5SAndroid Build Coastguard Workerconstexpr size_t kConvertedElementArrayBufferInitialSize = 1024 * 8; 26*8975f5c5SAndroid Build Coastguard Worker 27*8975f5c5SAndroid Build Coastguard Workertemplate <typename IndexType> 28*8975f5c5SAndroid Build Coastguard Workerangle::Result GetFirstLastIndices(const IndexType *indices, 29*8975f5c5SAndroid Build Coastguard Worker size_t count, 30*8975f5c5SAndroid Build Coastguard Worker std::pair<uint32_t, uint32_t> *outIndices) 31*8975f5c5SAndroid Build Coastguard Worker{ 32*8975f5c5SAndroid Build Coastguard Worker IndexType first, last; 33*8975f5c5SAndroid Build Coastguard Worker // Use memcpy to avoid unaligned memory access crash: 34*8975f5c5SAndroid Build Coastguard Worker memcpy(&first, &indices[0], sizeof(first)); 35*8975f5c5SAndroid Build Coastguard Worker memcpy(&last, &indices[count - 1], sizeof(last)); 36*8975f5c5SAndroid Build Coastguard Worker 37*8975f5c5SAndroid Build Coastguard Worker outIndices->first = first; 38*8975f5c5SAndroid Build Coastguard Worker outIndices->second = last; 39*8975f5c5SAndroid Build Coastguard Worker 40*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 41*8975f5c5SAndroid Build Coastguard Worker} 42*8975f5c5SAndroid Build Coastguard Worker 43*8975f5c5SAndroid Build Coastguard Workerbool isOffsetAndSizeMetalBlitCompatible(size_t offset, size_t size) 44*8975f5c5SAndroid Build Coastguard Worker{ 45*8975f5c5SAndroid Build Coastguard Worker // Metal requires offset and size to be multiples of 4 46*8975f5c5SAndroid Build Coastguard Worker return offset % 4 == 0 && size % 4 == 0; 47*8975f5c5SAndroid Build Coastguard Worker} 48*8975f5c5SAndroid Build Coastguard Worker 49*8975f5c5SAndroid Build Coastguard Worker} // namespace 50*8975f5c5SAndroid Build Coastguard Worker 51*8975f5c5SAndroid Build Coastguard Worker// ConversionBufferMtl implementation. 52*8975f5c5SAndroid Build Coastguard WorkerConversionBufferMtl::ConversionBufferMtl(ContextMtl *contextMtl, 53*8975f5c5SAndroid Build Coastguard Worker size_t initialSize, 54*8975f5c5SAndroid Build Coastguard Worker size_t alignment) 55*8975f5c5SAndroid Build Coastguard Worker : dirty(true), convertedBuffer(nullptr), convertedOffset(0) 56*8975f5c5SAndroid Build Coastguard Worker{ 57*8975f5c5SAndroid Build Coastguard Worker data.initialize(contextMtl, initialSize, alignment, 0); 58*8975f5c5SAndroid Build Coastguard Worker} 59*8975f5c5SAndroid Build Coastguard Worker 60*8975f5c5SAndroid Build Coastguard WorkerConversionBufferMtl::~ConversionBufferMtl() = default; 61*8975f5c5SAndroid Build Coastguard Worker 62*8975f5c5SAndroid Build Coastguard Worker// IndexConversionBufferMtl implementation. 63*8975f5c5SAndroid Build Coastguard WorkerIndexConversionBufferMtl::IndexConversionBufferMtl(ContextMtl *context, 64*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType elemTypeIn, 65*8975f5c5SAndroid Build Coastguard Worker bool primitiveRestartEnabledIn, 66*8975f5c5SAndroid Build Coastguard Worker size_t offsetIn) 67*8975f5c5SAndroid Build Coastguard Worker : ConversionBufferMtl(context, 68*8975f5c5SAndroid Build Coastguard Worker kConvertedElementArrayBufferInitialSize, 69*8975f5c5SAndroid Build Coastguard Worker mtl::kIndexBufferOffsetAlignment), 70*8975f5c5SAndroid Build Coastguard Worker elemType(elemTypeIn), 71*8975f5c5SAndroid Build Coastguard Worker offset(offsetIn), 72*8975f5c5SAndroid Build Coastguard Worker primitiveRestartEnabled(primitiveRestartEnabledIn) 73*8975f5c5SAndroid Build Coastguard Worker{} 74*8975f5c5SAndroid Build Coastguard Worker 75*8975f5c5SAndroid Build Coastguard WorkerIndexRange IndexConversionBufferMtl::getRangeForConvertedBuffer(size_t count) 76*8975f5c5SAndroid Build Coastguard Worker{ 77*8975f5c5SAndroid Build Coastguard Worker return IndexRange{0, count}; 78*8975f5c5SAndroid Build Coastguard Worker} 79*8975f5c5SAndroid Build Coastguard Worker 80*8975f5c5SAndroid Build Coastguard Worker// UniformConversionBufferMtl implementation 81*8975f5c5SAndroid Build Coastguard WorkerUniformConversionBufferMtl::UniformConversionBufferMtl(ContextMtl *context, 82*8975f5c5SAndroid Build Coastguard Worker std::pair<size_t, size_t> offsetIn, 83*8975f5c5SAndroid Build Coastguard Worker size_t uniformBufferBlockSize) 84*8975f5c5SAndroid Build Coastguard Worker : ConversionBufferMtl(context, 0, mtl::kUniformBufferSettingOffsetMinAlignment), 85*8975f5c5SAndroid Build Coastguard Worker uniformBufferBlockSize(uniformBufferBlockSize), 86*8975f5c5SAndroid Build Coastguard Worker offset(offsetIn) 87*8975f5c5SAndroid Build Coastguard Worker{} 88*8975f5c5SAndroid Build Coastguard Worker 89*8975f5c5SAndroid Build Coastguard Worker// VertexConversionBufferMtl implementation. 90*8975f5c5SAndroid Build Coastguard WorkerVertexConversionBufferMtl::VertexConversionBufferMtl(ContextMtl *context, 91*8975f5c5SAndroid Build Coastguard Worker angle::FormatID formatIDIn, 92*8975f5c5SAndroid Build Coastguard Worker GLuint strideIn, 93*8975f5c5SAndroid Build Coastguard Worker size_t offsetIn) 94*8975f5c5SAndroid Build Coastguard Worker : ConversionBufferMtl(context, 0, mtl::kVertexAttribBufferStrideAlignment), 95*8975f5c5SAndroid Build Coastguard Worker formatID(formatIDIn), 96*8975f5c5SAndroid Build Coastguard Worker stride(strideIn), 97*8975f5c5SAndroid Build Coastguard Worker offset(offsetIn) 98*8975f5c5SAndroid Build Coastguard Worker{} 99*8975f5c5SAndroid Build Coastguard Worker 100*8975f5c5SAndroid Build Coastguard Worker// BufferMtl implementation 101*8975f5c5SAndroid Build Coastguard WorkerBufferMtl::BufferMtl(const gl::BufferState &state) : BufferImpl(state) {} 102*8975f5c5SAndroid Build Coastguard Worker 103*8975f5c5SAndroid Build Coastguard WorkerBufferMtl::~BufferMtl() {} 104*8975f5c5SAndroid Build Coastguard Worker 105*8975f5c5SAndroid Build Coastguard Workervoid BufferMtl::destroy(const gl::Context *context) 106*8975f5c5SAndroid Build Coastguard Worker{ 107*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 108*8975f5c5SAndroid Build Coastguard Worker mShadowCopy.clear(); 109*8975f5c5SAndroid Build Coastguard Worker 110*8975f5c5SAndroid Build Coastguard Worker // if there's a buffer, give it back to the buffer manager 111*8975f5c5SAndroid Build Coastguard Worker if (mBuffer) 112*8975f5c5SAndroid Build Coastguard Worker { 113*8975f5c5SAndroid Build Coastguard Worker contextMtl->getBufferManager().returnBuffer(contextMtl, mBuffer); 114*8975f5c5SAndroid Build Coastguard Worker mBuffer = nullptr; 115*8975f5c5SAndroid Build Coastguard Worker } 116*8975f5c5SAndroid Build Coastguard Worker 117*8975f5c5SAndroid Build Coastguard Worker clearConversionBuffers(); 118*8975f5c5SAndroid Build Coastguard Worker} 119*8975f5c5SAndroid Build Coastguard Worker 120*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::setData(const gl::Context *context, 121*8975f5c5SAndroid Build Coastguard Worker gl::BufferBinding target, 122*8975f5c5SAndroid Build Coastguard Worker const void *data, 123*8975f5c5SAndroid Build Coastguard Worker size_t intendedSize, 124*8975f5c5SAndroid Build Coastguard Worker gl::BufferUsage usage) 125*8975f5c5SAndroid Build Coastguard Worker{ 126*8975f5c5SAndroid Build Coastguard Worker return setDataImpl(context, target, data, intendedSize, usage); 127*8975f5c5SAndroid Build Coastguard Worker} 128*8975f5c5SAndroid Build Coastguard Worker 129*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::setSubData(const gl::Context *context, 130*8975f5c5SAndroid Build Coastguard Worker gl::BufferBinding target, 131*8975f5c5SAndroid Build Coastguard Worker const void *data, 132*8975f5c5SAndroid Build Coastguard Worker size_t size, 133*8975f5c5SAndroid Build Coastguard Worker size_t offset) 134*8975f5c5SAndroid Build Coastguard Worker{ 135*8975f5c5SAndroid Build Coastguard Worker return setSubDataImpl(context, data, size, offset); 136*8975f5c5SAndroid Build Coastguard Worker} 137*8975f5c5SAndroid Build Coastguard Worker 138*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::copySubData(const gl::Context *context, 139*8975f5c5SAndroid Build Coastguard Worker BufferImpl *source, 140*8975f5c5SAndroid Build Coastguard Worker GLintptr sourceOffset, 141*8975f5c5SAndroid Build Coastguard Worker GLintptr destOffset, 142*8975f5c5SAndroid Build Coastguard Worker GLsizeiptr size) 143*8975f5c5SAndroid Build Coastguard Worker{ 144*8975f5c5SAndroid Build Coastguard Worker if (!source) 145*8975f5c5SAndroid Build Coastguard Worker { 146*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 147*8975f5c5SAndroid Build Coastguard Worker } 148*8975f5c5SAndroid Build Coastguard Worker 149*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 150*8975f5c5SAndroid Build Coastguard Worker auto srcMtl = GetAs<BufferMtl>(source); 151*8975f5c5SAndroid Build Coastguard Worker 152*8975f5c5SAndroid Build Coastguard Worker markConversionBuffersDirty(); 153*8975f5c5SAndroid Build Coastguard Worker 154*8975f5c5SAndroid Build Coastguard Worker if (mShadowCopy.size() > 0) 155*8975f5c5SAndroid Build Coastguard Worker { 156*8975f5c5SAndroid Build Coastguard Worker if (srcMtl->clientShadowCopyDataNeedSync(contextMtl) || 157*8975f5c5SAndroid Build Coastguard Worker mBuffer->isBeingUsedByGPU(contextMtl)) 158*8975f5c5SAndroid Build Coastguard Worker { 159*8975f5c5SAndroid Build Coastguard Worker // If shadow copy requires a synchronization then use blit command instead. 160*8975f5c5SAndroid Build Coastguard Worker // It might break a pending render pass, but still faster than synchronization with 161*8975f5c5SAndroid Build Coastguard Worker // GPU. 162*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder(); 163*8975f5c5SAndroid Build Coastguard Worker blitEncoder->copyBuffer(srcMtl->getCurrentBuffer(), sourceOffset, mBuffer, destOffset, 164*8975f5c5SAndroid Build Coastguard Worker size); 165*8975f5c5SAndroid Build Coastguard Worker 166*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 167*8975f5c5SAndroid Build Coastguard Worker } 168*8975f5c5SAndroid Build Coastguard Worker return setSubDataImpl(context, srcMtl->getBufferDataReadOnly(contextMtl) + sourceOffset, 169*8975f5c5SAndroid Build Coastguard Worker size, destOffset); 170*8975f5c5SAndroid Build Coastguard Worker } 171*8975f5c5SAndroid Build Coastguard Worker 172*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *blitEncoder = contextMtl->getBlitCommandEncoder(); 173*8975f5c5SAndroid Build Coastguard Worker blitEncoder->copyBuffer(srcMtl->getCurrentBuffer(), sourceOffset, mBuffer, destOffset, size); 174*8975f5c5SAndroid Build Coastguard Worker 175*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 176*8975f5c5SAndroid Build Coastguard Worker} 177*8975f5c5SAndroid Build Coastguard Worker 178*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::map(const gl::Context *context, GLenum access, void **mapPtr) 179*8975f5c5SAndroid Build Coastguard Worker{ 180*8975f5c5SAndroid Build Coastguard Worker GLbitfield mapRangeAccess = 0; 181*8975f5c5SAndroid Build Coastguard Worker if ((access & GL_WRITE_ONLY_OES) != 0 || (access & GL_READ_WRITE) != 0) 182*8975f5c5SAndroid Build Coastguard Worker { 183*8975f5c5SAndroid Build Coastguard Worker mapRangeAccess |= GL_MAP_WRITE_BIT; 184*8975f5c5SAndroid Build Coastguard Worker } 185*8975f5c5SAndroid Build Coastguard Worker return mapRange(context, 0, size(), mapRangeAccess, mapPtr); 186*8975f5c5SAndroid Build Coastguard Worker} 187*8975f5c5SAndroid Build Coastguard Worker 188*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::mapRange(const gl::Context *context, 189*8975f5c5SAndroid Build Coastguard Worker size_t offset, 190*8975f5c5SAndroid Build Coastguard Worker size_t length, 191*8975f5c5SAndroid Build Coastguard Worker GLbitfield access, 192*8975f5c5SAndroid Build Coastguard Worker void **mapPtr) 193*8975f5c5SAndroid Build Coastguard Worker{ 194*8975f5c5SAndroid Build Coastguard Worker if (access & GL_MAP_INVALIDATE_BUFFER_BIT) 195*8975f5c5SAndroid Build Coastguard Worker { 196*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(setDataImpl(context, gl::BufferBinding::InvalidEnum, nullptr, size(), 197*8975f5c5SAndroid Build Coastguard Worker mState.getUsage())); 198*8975f5c5SAndroid Build Coastguard Worker } 199*8975f5c5SAndroid Build Coastguard Worker 200*8975f5c5SAndroid Build Coastguard Worker if (mapPtr) 201*8975f5c5SAndroid Build Coastguard Worker { 202*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 203*8975f5c5SAndroid Build Coastguard Worker if (mShadowCopy.size() == 0) 204*8975f5c5SAndroid Build Coastguard Worker { 205*8975f5c5SAndroid Build Coastguard Worker *mapPtr = mBuffer->mapWithOpt(contextMtl, (access & GL_MAP_WRITE_BIT) == 0, 206*8975f5c5SAndroid Build Coastguard Worker access & GL_MAP_UNSYNCHRONIZED_BIT) + 207*8975f5c5SAndroid Build Coastguard Worker offset; 208*8975f5c5SAndroid Build Coastguard Worker } 209*8975f5c5SAndroid Build Coastguard Worker else 210*8975f5c5SAndroid Build Coastguard Worker { 211*8975f5c5SAndroid Build Coastguard Worker *mapPtr = syncAndObtainShadowCopy(contextMtl) + offset; 212*8975f5c5SAndroid Build Coastguard Worker } 213*8975f5c5SAndroid Build Coastguard Worker } 214*8975f5c5SAndroid Build Coastguard Worker 215*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 216*8975f5c5SAndroid Build Coastguard Worker} 217*8975f5c5SAndroid Build Coastguard Worker 218*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::unmap(const gl::Context *context, GLboolean *result) 219*8975f5c5SAndroid Build Coastguard Worker{ 220*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 221*8975f5c5SAndroid Build Coastguard Worker size_t offset = static_cast<size_t>(mState.getMapOffset()); 222*8975f5c5SAndroid Build Coastguard Worker size_t len = static_cast<size_t>(mState.getMapLength()); 223*8975f5c5SAndroid Build Coastguard Worker 224*8975f5c5SAndroid Build Coastguard Worker markConversionBuffersDirty(); 225*8975f5c5SAndroid Build Coastguard Worker 226*8975f5c5SAndroid Build Coastguard Worker if (mShadowCopy.size() == 0) 227*8975f5c5SAndroid Build Coastguard Worker { 228*8975f5c5SAndroid Build Coastguard Worker ASSERT(mBuffer); 229*8975f5c5SAndroid Build Coastguard Worker if (mState.getAccessFlags() & GL_MAP_WRITE_BIT) 230*8975f5c5SAndroid Build Coastguard Worker { 231*8975f5c5SAndroid Build Coastguard Worker mBuffer->unmapAndFlushSubset(contextMtl, offset, len); 232*8975f5c5SAndroid Build Coastguard Worker } 233*8975f5c5SAndroid Build Coastguard Worker else 234*8975f5c5SAndroid Build Coastguard Worker { 235*8975f5c5SAndroid Build Coastguard Worker // Buffer is already mapped with readonly flag, so just unmap it, no flushing will 236*8975f5c5SAndroid Build Coastguard Worker // occur. 237*8975f5c5SAndroid Build Coastguard Worker mBuffer->unmap(contextMtl); 238*8975f5c5SAndroid Build Coastguard Worker } 239*8975f5c5SAndroid Build Coastguard Worker } 240*8975f5c5SAndroid Build Coastguard Worker else 241*8975f5c5SAndroid Build Coastguard Worker { 242*8975f5c5SAndroid Build Coastguard Worker if (mState.getAccessFlags() & GL_MAP_UNSYNCHRONIZED_BIT) 243*8975f5c5SAndroid Build Coastguard Worker { 244*8975f5c5SAndroid Build Coastguard Worker // Copy the mapped region without synchronization with GPU 245*8975f5c5SAndroid Build Coastguard Worker uint8_t *ptr = 246*8975f5c5SAndroid Build Coastguard Worker mBuffer->mapWithOpt(contextMtl, /* readonly */ false, /* noSync */ true) + offset; 247*8975f5c5SAndroid Build Coastguard Worker std::copy(mShadowCopy.data() + offset, mShadowCopy.data() + offset + len, ptr); 248*8975f5c5SAndroid Build Coastguard Worker mBuffer->unmapAndFlushSubset(contextMtl, offset, len); 249*8975f5c5SAndroid Build Coastguard Worker } 250*8975f5c5SAndroid Build Coastguard Worker else 251*8975f5c5SAndroid Build Coastguard Worker { 252*8975f5c5SAndroid Build Coastguard Worker // commit shadow copy data to GPU synchronously 253*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(commitShadowCopy(contextMtl)); 254*8975f5c5SAndroid Build Coastguard Worker } 255*8975f5c5SAndroid Build Coastguard Worker } 256*8975f5c5SAndroid Build Coastguard Worker 257*8975f5c5SAndroid Build Coastguard Worker if (result) 258*8975f5c5SAndroid Build Coastguard Worker { 259*8975f5c5SAndroid Build Coastguard Worker *result = true; 260*8975f5c5SAndroid Build Coastguard Worker } 261*8975f5c5SAndroid Build Coastguard Worker 262*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 263*8975f5c5SAndroid Build Coastguard Worker} 264*8975f5c5SAndroid Build Coastguard Worker 265*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::getIndexRange(const gl::Context *context, 266*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType type, 267*8975f5c5SAndroid Build Coastguard Worker size_t offset, 268*8975f5c5SAndroid Build Coastguard Worker size_t count, 269*8975f5c5SAndroid Build Coastguard Worker bool primitiveRestartEnabled, 270*8975f5c5SAndroid Build Coastguard Worker gl::IndexRange *outRange) 271*8975f5c5SAndroid Build Coastguard Worker{ 272*8975f5c5SAndroid Build Coastguard Worker const uint8_t *indices = getBufferDataReadOnly(mtl::GetImpl(context)) + offset; 273*8975f5c5SAndroid Build Coastguard Worker 274*8975f5c5SAndroid Build Coastguard Worker *outRange = gl::ComputeIndexRange(type, indices, count, primitiveRestartEnabled); 275*8975f5c5SAndroid Build Coastguard Worker 276*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 277*8975f5c5SAndroid Build Coastguard Worker} 278*8975f5c5SAndroid Build Coastguard Worker 279*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::getFirstLastIndices(ContextMtl *contextMtl, 280*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType type, 281*8975f5c5SAndroid Build Coastguard Worker size_t offset, 282*8975f5c5SAndroid Build Coastguard Worker size_t count, 283*8975f5c5SAndroid Build Coastguard Worker std::pair<uint32_t, uint32_t> *outIndices) 284*8975f5c5SAndroid Build Coastguard Worker{ 285*8975f5c5SAndroid Build Coastguard Worker const uint8_t *indices = getBufferDataReadOnly(contextMtl) + offset; 286*8975f5c5SAndroid Build Coastguard Worker 287*8975f5c5SAndroid Build Coastguard Worker switch (type) 288*8975f5c5SAndroid Build Coastguard Worker { 289*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedByte: 290*8975f5c5SAndroid Build Coastguard Worker return GetFirstLastIndices(static_cast<const GLubyte *>(indices), count, outIndices); 291*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedShort: 292*8975f5c5SAndroid Build Coastguard Worker return GetFirstLastIndices(reinterpret_cast<const GLushort *>(indices), count, 293*8975f5c5SAndroid Build Coastguard Worker outIndices); 294*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedInt: 295*8975f5c5SAndroid Build Coastguard Worker return GetFirstLastIndices(reinterpret_cast<const GLuint *>(indices), count, 296*8975f5c5SAndroid Build Coastguard Worker outIndices); 297*8975f5c5SAndroid Build Coastguard Worker default: 298*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE(); 299*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Stop; 300*8975f5c5SAndroid Build Coastguard Worker } 301*8975f5c5SAndroid Build Coastguard Worker} 302*8975f5c5SAndroid Build Coastguard Worker 303*8975f5c5SAndroid Build Coastguard Workervoid BufferMtl::onDataChanged() 304*8975f5c5SAndroid Build Coastguard Worker{ 305*8975f5c5SAndroid Build Coastguard Worker markConversionBuffersDirty(); 306*8975f5c5SAndroid Build Coastguard Worker} 307*8975f5c5SAndroid Build Coastguard Worker 308*8975f5c5SAndroid Build Coastguard Workerconst uint8_t *BufferMtl::getBufferDataReadOnly(ContextMtl *contextMtl) 309*8975f5c5SAndroid Build Coastguard Worker{ 310*8975f5c5SAndroid Build Coastguard Worker if (mShadowCopy.size() == 0) 311*8975f5c5SAndroid Build Coastguard Worker { 312*8975f5c5SAndroid Build Coastguard Worker // Don't need shadow copy in this case, use the buffer directly 313*8975f5c5SAndroid Build Coastguard Worker return mBuffer->mapReadOnly(contextMtl); 314*8975f5c5SAndroid Build Coastguard Worker } 315*8975f5c5SAndroid Build Coastguard Worker return syncAndObtainShadowCopy(contextMtl); 316*8975f5c5SAndroid Build Coastguard Worker} 317*8975f5c5SAndroid Build Coastguard Worker 318*8975f5c5SAndroid Build Coastguard Workerbool BufferMtl::clientShadowCopyDataNeedSync(ContextMtl *contextMtl) 319*8975f5c5SAndroid Build Coastguard Worker{ 320*8975f5c5SAndroid Build Coastguard Worker return mBuffer->isCPUReadMemDirty(); 321*8975f5c5SAndroid Build Coastguard Worker} 322*8975f5c5SAndroid Build Coastguard Worker 323*8975f5c5SAndroid Build Coastguard Workervoid BufferMtl::ensureShadowCopySyncedFromGPU(ContextMtl *contextMtl) 324*8975f5c5SAndroid Build Coastguard Worker{ 325*8975f5c5SAndroid Build Coastguard Worker if (mBuffer->isCPUReadMemDirty()) 326*8975f5c5SAndroid Build Coastguard Worker { 327*8975f5c5SAndroid Build Coastguard Worker const uint8_t *ptr = mBuffer->mapReadOnly(contextMtl); 328*8975f5c5SAndroid Build Coastguard Worker memcpy(mShadowCopy.data(), ptr, size()); 329*8975f5c5SAndroid Build Coastguard Worker mBuffer->unmap(contextMtl); 330*8975f5c5SAndroid Build Coastguard Worker 331*8975f5c5SAndroid Build Coastguard Worker mBuffer->resetCPUReadMemDirty(); 332*8975f5c5SAndroid Build Coastguard Worker } 333*8975f5c5SAndroid Build Coastguard Worker} 334*8975f5c5SAndroid Build Coastguard Workeruint8_t *BufferMtl::syncAndObtainShadowCopy(ContextMtl *contextMtl) 335*8975f5c5SAndroid Build Coastguard Worker{ 336*8975f5c5SAndroid Build Coastguard Worker ASSERT(mShadowCopy.size()); 337*8975f5c5SAndroid Build Coastguard Worker 338*8975f5c5SAndroid Build Coastguard Worker ensureShadowCopySyncedFromGPU(contextMtl); 339*8975f5c5SAndroid Build Coastguard Worker 340*8975f5c5SAndroid Build Coastguard Worker return mShadowCopy.data(); 341*8975f5c5SAndroid Build Coastguard Worker} 342*8975f5c5SAndroid Build Coastguard Worker 343*8975f5c5SAndroid Build Coastguard WorkerConversionBufferMtl *BufferMtl::getVertexConversionBuffer(ContextMtl *context, 344*8975f5c5SAndroid Build Coastguard Worker angle::FormatID formatID, 345*8975f5c5SAndroid Build Coastguard Worker GLuint stride, 346*8975f5c5SAndroid Build Coastguard Worker size_t offset) 347*8975f5c5SAndroid Build Coastguard Worker{ 348*8975f5c5SAndroid Build Coastguard Worker for (VertexConversionBufferMtl &buffer : mVertexConversionBuffers) 349*8975f5c5SAndroid Build Coastguard Worker { 350*8975f5c5SAndroid Build Coastguard Worker if (buffer.formatID == formatID && buffer.stride == stride && buffer.offset <= offset && 351*8975f5c5SAndroid Build Coastguard Worker buffer.offset % buffer.stride == offset % stride) 352*8975f5c5SAndroid Build Coastguard Worker { 353*8975f5c5SAndroid Build Coastguard Worker return &buffer; 354*8975f5c5SAndroid Build Coastguard Worker } 355*8975f5c5SAndroid Build Coastguard Worker } 356*8975f5c5SAndroid Build Coastguard Worker 357*8975f5c5SAndroid Build Coastguard Worker mVertexConversionBuffers.emplace_back(context, formatID, stride, offset); 358*8975f5c5SAndroid Build Coastguard Worker ConversionBufferMtl *conv = &mVertexConversionBuffers.back(); 359*8975f5c5SAndroid Build Coastguard Worker const angle::Format &angleFormat = angle::Format::Get(formatID); 360*8975f5c5SAndroid Build Coastguard Worker conv->data.updateAlignment(context, angleFormat.pixelBytes); 361*8975f5c5SAndroid Build Coastguard Worker 362*8975f5c5SAndroid Build Coastguard Worker return conv; 363*8975f5c5SAndroid Build Coastguard Worker} 364*8975f5c5SAndroid Build Coastguard Worker 365*8975f5c5SAndroid Build Coastguard WorkerIndexConversionBufferMtl *BufferMtl::getIndexConversionBuffer(ContextMtl *context, 366*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType elemType, 367*8975f5c5SAndroid Build Coastguard Worker bool primitiveRestartEnabled, 368*8975f5c5SAndroid Build Coastguard Worker size_t offset) 369*8975f5c5SAndroid Build Coastguard Worker{ 370*8975f5c5SAndroid Build Coastguard Worker for (auto &buffer : mIndexConversionBuffers) 371*8975f5c5SAndroid Build Coastguard Worker { 372*8975f5c5SAndroid Build Coastguard Worker if (buffer.elemType == elemType && buffer.offset == offset && 373*8975f5c5SAndroid Build Coastguard Worker buffer.primitiveRestartEnabled == primitiveRestartEnabled) 374*8975f5c5SAndroid Build Coastguard Worker { 375*8975f5c5SAndroid Build Coastguard Worker return &buffer; 376*8975f5c5SAndroid Build Coastguard Worker } 377*8975f5c5SAndroid Build Coastguard Worker } 378*8975f5c5SAndroid Build Coastguard Worker 379*8975f5c5SAndroid Build Coastguard Worker mIndexConversionBuffers.emplace_back(context, elemType, primitiveRestartEnabled, offset); 380*8975f5c5SAndroid Build Coastguard Worker return &mIndexConversionBuffers.back(); 381*8975f5c5SAndroid Build Coastguard Worker} 382*8975f5c5SAndroid Build Coastguard Worker 383*8975f5c5SAndroid Build Coastguard WorkerConversionBufferMtl *BufferMtl::getUniformConversionBuffer(ContextMtl *context, 384*8975f5c5SAndroid Build Coastguard Worker std::pair<size_t, size_t> offset, 385*8975f5c5SAndroid Build Coastguard Worker size_t stdSize) 386*8975f5c5SAndroid Build Coastguard Worker{ 387*8975f5c5SAndroid Build Coastguard Worker for (UniformConversionBufferMtl &buffer : mUniformConversionBuffers) 388*8975f5c5SAndroid Build Coastguard Worker { 389*8975f5c5SAndroid Build Coastguard Worker if (buffer.offset.first == offset.first && buffer.uniformBufferBlockSize == stdSize) 390*8975f5c5SAndroid Build Coastguard Worker { 391*8975f5c5SAndroid Build Coastguard Worker if (buffer.offset.second <= offset.second && 392*8975f5c5SAndroid Build Coastguard Worker (offset.second - buffer.offset.second) % buffer.uniformBufferBlockSize == 0) 393*8975f5c5SAndroid Build Coastguard Worker return &buffer; 394*8975f5c5SAndroid Build Coastguard Worker } 395*8975f5c5SAndroid Build Coastguard Worker } 396*8975f5c5SAndroid Build Coastguard Worker 397*8975f5c5SAndroid Build Coastguard Worker mUniformConversionBuffers.emplace_back(context, offset, stdSize); 398*8975f5c5SAndroid Build Coastguard Worker return &mUniformConversionBuffers.back(); 399*8975f5c5SAndroid Build Coastguard Worker} 400*8975f5c5SAndroid Build Coastguard Worker 401*8975f5c5SAndroid Build Coastguard Workervoid BufferMtl::markConversionBuffersDirty() 402*8975f5c5SAndroid Build Coastguard Worker{ 403*8975f5c5SAndroid Build Coastguard Worker for (VertexConversionBufferMtl &buffer : mVertexConversionBuffers) 404*8975f5c5SAndroid Build Coastguard Worker { 405*8975f5c5SAndroid Build Coastguard Worker buffer.dirty = true; 406*8975f5c5SAndroid Build Coastguard Worker buffer.convertedBuffer = nullptr; 407*8975f5c5SAndroid Build Coastguard Worker buffer.convertedOffset = 0; 408*8975f5c5SAndroid Build Coastguard Worker } 409*8975f5c5SAndroid Build Coastguard Worker 410*8975f5c5SAndroid Build Coastguard Worker for (IndexConversionBufferMtl &buffer : mIndexConversionBuffers) 411*8975f5c5SAndroid Build Coastguard Worker { 412*8975f5c5SAndroid Build Coastguard Worker buffer.dirty = true; 413*8975f5c5SAndroid Build Coastguard Worker buffer.convertedBuffer = nullptr; 414*8975f5c5SAndroid Build Coastguard Worker buffer.convertedOffset = 0; 415*8975f5c5SAndroid Build Coastguard Worker } 416*8975f5c5SAndroid Build Coastguard Worker 417*8975f5c5SAndroid Build Coastguard Worker for (UniformConversionBufferMtl &buffer : mUniformConversionBuffers) 418*8975f5c5SAndroid Build Coastguard Worker { 419*8975f5c5SAndroid Build Coastguard Worker buffer.dirty = true; 420*8975f5c5SAndroid Build Coastguard Worker buffer.convertedBuffer = nullptr; 421*8975f5c5SAndroid Build Coastguard Worker buffer.convertedOffset = 0; 422*8975f5c5SAndroid Build Coastguard Worker } 423*8975f5c5SAndroid Build Coastguard Worker mRestartRangeCache.reset(); 424*8975f5c5SAndroid Build Coastguard Worker} 425*8975f5c5SAndroid Build Coastguard Worker 426*8975f5c5SAndroid Build Coastguard Workervoid BufferMtl::clearConversionBuffers() 427*8975f5c5SAndroid Build Coastguard Worker{ 428*8975f5c5SAndroid Build Coastguard Worker mVertexConversionBuffers.clear(); 429*8975f5c5SAndroid Build Coastguard Worker mIndexConversionBuffers.clear(); 430*8975f5c5SAndroid Build Coastguard Worker mUniformConversionBuffers.clear(); 431*8975f5c5SAndroid Build Coastguard Worker mRestartRangeCache.reset(); 432*8975f5c5SAndroid Build Coastguard Worker} 433*8975f5c5SAndroid Build Coastguard Worker 434*8975f5c5SAndroid Build Coastguard Workertemplate <typename T> 435*8975f5c5SAndroid Build Coastguard Workerstatic std::vector<IndexRange> calculateRestartRanges(ContextMtl *ctx, mtl::BufferRef idxBuffer) 436*8975f5c5SAndroid Build Coastguard Worker{ 437*8975f5c5SAndroid Build Coastguard Worker std::vector<IndexRange> result; 438*8975f5c5SAndroid Build Coastguard Worker const T *bufferData = reinterpret_cast<const T *>(idxBuffer->mapReadOnly(ctx)); 439*8975f5c5SAndroid Build Coastguard Worker const size_t numIndices = idxBuffer->size() / sizeof(T); 440*8975f5c5SAndroid Build Coastguard Worker constexpr T restartMarker = std::numeric_limits<T>::max(); 441*8975f5c5SAndroid Build Coastguard Worker for (size_t i = 0; i < numIndices; ++i) 442*8975f5c5SAndroid Build Coastguard Worker { 443*8975f5c5SAndroid Build Coastguard Worker // Find the start of the restart range, i.e. first index with value of restart marker. 444*8975f5c5SAndroid Build Coastguard Worker if (bufferData[i] != restartMarker) 445*8975f5c5SAndroid Build Coastguard Worker continue; 446*8975f5c5SAndroid Build Coastguard Worker size_t restartBegin = i; 447*8975f5c5SAndroid Build Coastguard Worker // Find the end of the restart range, i.e. last index with value of restart marker. 448*8975f5c5SAndroid Build Coastguard Worker do 449*8975f5c5SAndroid Build Coastguard Worker { 450*8975f5c5SAndroid Build Coastguard Worker ++i; 451*8975f5c5SAndroid Build Coastguard Worker } while (i < numIndices && bufferData[i] == restartMarker); 452*8975f5c5SAndroid Build Coastguard Worker result.emplace_back(restartBegin, i - 1); 453*8975f5c5SAndroid Build Coastguard Worker } 454*8975f5c5SAndroid Build Coastguard Worker idxBuffer->unmap(ctx); 455*8975f5c5SAndroid Build Coastguard Worker return result; 456*8975f5c5SAndroid Build Coastguard Worker} 457*8975f5c5SAndroid Build Coastguard Worker 458*8975f5c5SAndroid Build Coastguard Workerconst std::vector<IndexRange> &BufferMtl::getRestartIndices(ContextMtl *ctx, 459*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType indexType) 460*8975f5c5SAndroid Build Coastguard Worker{ 461*8975f5c5SAndroid Build Coastguard Worker if (!mRestartRangeCache || mRestartRangeCache->indexType != indexType) 462*8975f5c5SAndroid Build Coastguard Worker { 463*8975f5c5SAndroid Build Coastguard Worker mRestartRangeCache.reset(); 464*8975f5c5SAndroid Build Coastguard Worker std::vector<IndexRange> ranges; 465*8975f5c5SAndroid Build Coastguard Worker switch (indexType) 466*8975f5c5SAndroid Build Coastguard Worker { 467*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedByte: 468*8975f5c5SAndroid Build Coastguard Worker ranges = calculateRestartRanges<uint8_t>(ctx, getCurrentBuffer()); 469*8975f5c5SAndroid Build Coastguard Worker break; 470*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedShort: 471*8975f5c5SAndroid Build Coastguard Worker ranges = calculateRestartRanges<uint16_t>(ctx, getCurrentBuffer()); 472*8975f5c5SAndroid Build Coastguard Worker break; 473*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedInt: 474*8975f5c5SAndroid Build Coastguard Worker ranges = calculateRestartRanges<uint32_t>(ctx, getCurrentBuffer()); 475*8975f5c5SAndroid Build Coastguard Worker break; 476*8975f5c5SAndroid Build Coastguard Worker default: 477*8975f5c5SAndroid Build Coastguard Worker ASSERT(false); 478*8975f5c5SAndroid Build Coastguard Worker } 479*8975f5c5SAndroid Build Coastguard Worker mRestartRangeCache.emplace(std::move(ranges), indexType); 480*8975f5c5SAndroid Build Coastguard Worker } 481*8975f5c5SAndroid Build Coastguard Worker return mRestartRangeCache->ranges; 482*8975f5c5SAndroid Build Coastguard Worker} 483*8975f5c5SAndroid Build Coastguard Worker 484*8975f5c5SAndroid Build Coastguard Workerconst std::vector<IndexRange> BufferMtl::getRestartIndicesFromClientData( 485*8975f5c5SAndroid Build Coastguard Worker ContextMtl *ctx, 486*8975f5c5SAndroid Build Coastguard Worker gl::DrawElementsType indexType, 487*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef idxBuffer) 488*8975f5c5SAndroid Build Coastguard Worker{ 489*8975f5c5SAndroid Build Coastguard Worker std::vector<IndexRange> restartIndices; 490*8975f5c5SAndroid Build Coastguard Worker switch (indexType) 491*8975f5c5SAndroid Build Coastguard Worker { 492*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedByte: 493*8975f5c5SAndroid Build Coastguard Worker restartIndices = calculateRestartRanges<uint8_t>(ctx, idxBuffer); 494*8975f5c5SAndroid Build Coastguard Worker break; 495*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedShort: 496*8975f5c5SAndroid Build Coastguard Worker restartIndices = calculateRestartRanges<uint16_t>(ctx, idxBuffer); 497*8975f5c5SAndroid Build Coastguard Worker break; 498*8975f5c5SAndroid Build Coastguard Worker case gl::DrawElementsType::UnsignedInt: 499*8975f5c5SAndroid Build Coastguard Worker restartIndices = calculateRestartRanges<uint32_t>(ctx, idxBuffer); 500*8975f5c5SAndroid Build Coastguard Worker break; 501*8975f5c5SAndroid Build Coastguard Worker default: 502*8975f5c5SAndroid Build Coastguard Worker ASSERT(false); 503*8975f5c5SAndroid Build Coastguard Worker } 504*8975f5c5SAndroid Build Coastguard Worker return restartIndices; 505*8975f5c5SAndroid Build Coastguard Worker} 506*8975f5c5SAndroid Build Coastguard Worker 507*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::allocateNewMetalBuffer(ContextMtl *contextMtl, 508*8975f5c5SAndroid Build Coastguard Worker MTLStorageMode storageMode, 509*8975f5c5SAndroid Build Coastguard Worker size_t size, 510*8975f5c5SAndroid Build Coastguard Worker bool returnOldBufferImmediately) 511*8975f5c5SAndroid Build Coastguard Worker{ 512*8975f5c5SAndroid Build Coastguard Worker mtl::BufferManager &bufferManager = contextMtl->getBufferManager(); 513*8975f5c5SAndroid Build Coastguard Worker if (returnOldBufferImmediately && mBuffer) 514*8975f5c5SAndroid Build Coastguard Worker { 515*8975f5c5SAndroid Build Coastguard Worker // Return the current buffer to the buffer manager 516*8975f5c5SAndroid Build Coastguard Worker // It will not be re-used until it's no longer in use. 517*8975f5c5SAndroid Build Coastguard Worker bufferManager.returnBuffer(contextMtl, mBuffer); 518*8975f5c5SAndroid Build Coastguard Worker mBuffer = nullptr; 519*8975f5c5SAndroid Build Coastguard Worker } 520*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(bufferManager.getBuffer(contextMtl, storageMode, size, mBuffer)); 521*8975f5c5SAndroid Build Coastguard Worker 522*8975f5c5SAndroid Build Coastguard Worker onStateChange(angle::SubjectMessage::InternalMemoryAllocationChanged); 523*8975f5c5SAndroid Build Coastguard Worker 524*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 525*8975f5c5SAndroid Build Coastguard Worker} 526*8975f5c5SAndroid Build Coastguard Worker 527*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::setDataImpl(const gl::Context *context, 528*8975f5c5SAndroid Build Coastguard Worker gl::BufferBinding target, 529*8975f5c5SAndroid Build Coastguard Worker const void *data, 530*8975f5c5SAndroid Build Coastguard Worker size_t intendedSize, 531*8975f5c5SAndroid Build Coastguard Worker gl::BufferUsage usage) 532*8975f5c5SAndroid Build Coastguard Worker{ 533*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 534*8975f5c5SAndroid Build Coastguard Worker const angle::FeaturesMtl &features = contextMtl->getDisplay()->getFeatures(); 535*8975f5c5SAndroid Build Coastguard Worker 536*8975f5c5SAndroid Build Coastguard Worker // Invalidate conversion buffers 537*8975f5c5SAndroid Build Coastguard Worker if (mState.getSize() != static_cast<GLint64>(intendedSize)) 538*8975f5c5SAndroid Build Coastguard Worker { 539*8975f5c5SAndroid Build Coastguard Worker clearConversionBuffers(); 540*8975f5c5SAndroid Build Coastguard Worker } 541*8975f5c5SAndroid Build Coastguard Worker else 542*8975f5c5SAndroid Build Coastguard Worker { 543*8975f5c5SAndroid Build Coastguard Worker markConversionBuffersDirty(); 544*8975f5c5SAndroid Build Coastguard Worker } 545*8975f5c5SAndroid Build Coastguard Worker 546*8975f5c5SAndroid Build Coastguard Worker mUsage = usage; 547*8975f5c5SAndroid Build Coastguard Worker mGLSize = intendedSize; 548*8975f5c5SAndroid Build Coastguard Worker size_t adjustedSize = std::max<size_t>(1, intendedSize); 549*8975f5c5SAndroid Build Coastguard Worker 550*8975f5c5SAndroid Build Coastguard Worker // Ensures no validation layer issues in std140 with data types like vec3 being 12 bytes vs 16 551*8975f5c5SAndroid Build Coastguard Worker // in MSL. 552*8975f5c5SAndroid Build Coastguard Worker if (target == gl::BufferBinding::Uniform) 553*8975f5c5SAndroid Build Coastguard Worker { 554*8975f5c5SAndroid Build Coastguard Worker // This doesn't work! A buffer can be allocated on ARRAY_BUFFER and used in UNIFORM_BUFFER 555*8975f5c5SAndroid Build Coastguard Worker // TODO(anglebug.com/42266052) 556*8975f5c5SAndroid Build Coastguard Worker adjustedSize = roundUpPow2(adjustedSize, (size_t)16); 557*8975f5c5SAndroid Build Coastguard Worker } 558*8975f5c5SAndroid Build Coastguard Worker 559*8975f5c5SAndroid Build Coastguard Worker // Re-create the buffer 560*8975f5c5SAndroid Build Coastguard Worker auto storageMode = mtl::Buffer::getStorageModeForUsage(contextMtl, usage); 561*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(allocateNewMetalBuffer(contextMtl, storageMode, adjustedSize, 562*8975f5c5SAndroid Build Coastguard Worker /*returnOldBufferImmediately=*/true)); 563*8975f5c5SAndroid Build Coastguard Worker 564*8975f5c5SAndroid Build Coastguard Worker#ifndef NDEBUG 565*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_OBJC_SCOPE 566*8975f5c5SAndroid Build Coastguard Worker { 567*8975f5c5SAndroid Build Coastguard Worker mBuffer->get().label = [NSString stringWithFormat:@"BufferMtl=%p", this]; 568*8975f5c5SAndroid Build Coastguard Worker } 569*8975f5c5SAndroid Build Coastguard Worker#endif 570*8975f5c5SAndroid Build Coastguard Worker 571*8975f5c5SAndroid Build Coastguard Worker // We may use shadow copy to maintain consistent data between buffers in pool 572*8975f5c5SAndroid Build Coastguard Worker size_t shadowSize = (!features.preferCpuForBuffersubdata.enabled && 573*8975f5c5SAndroid Build Coastguard Worker features.useShadowBuffersWhenAppropriate.enabled && 574*8975f5c5SAndroid Build Coastguard Worker adjustedSize <= mtl::kSharedMemBufferMaxBufSizeHint) 575*8975f5c5SAndroid Build Coastguard Worker ? adjustedSize 576*8975f5c5SAndroid Build Coastguard Worker : 0; 577*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_CHECK(contextMtl, mShadowCopy.resize(shadowSize), GL_OUT_OF_MEMORY); 578*8975f5c5SAndroid Build Coastguard Worker 579*8975f5c5SAndroid Build Coastguard Worker if (data) 580*8975f5c5SAndroid Build Coastguard Worker { 581*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(setSubDataImpl(context, data, intendedSize, 0)); 582*8975f5c5SAndroid Build Coastguard Worker } 583*8975f5c5SAndroid Build Coastguard Worker 584*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 585*8975f5c5SAndroid Build Coastguard Worker} 586*8975f5c5SAndroid Build Coastguard Worker 587*8975f5c5SAndroid Build Coastguard Worker// states: 588*8975f5c5SAndroid Build Coastguard Worker// * The buffer is not use 589*8975f5c5SAndroid Build Coastguard Worker// 590*8975f5c5SAndroid Build Coastguard Worker// safe = true 591*8975f5c5SAndroid Build Coastguard Worker// 592*8975f5c5SAndroid Build Coastguard Worker// * The buffer has a pending blit 593*8975f5c5SAndroid Build Coastguard Worker// 594*8975f5c5SAndroid Build Coastguard Worker// In this case, as long as we are only reading from it 595*8975f5c5SAndroid Build Coastguard Worker// via blit to a new buffer our blits will happen after existing 596*8975f5c5SAndroid Build Coastguard Worker// blits 597*8975f5c5SAndroid Build Coastguard Worker// 598*8975f5c5SAndroid Build Coastguard Worker// safe = true 599*8975f5c5SAndroid Build Coastguard Worker// 600*8975f5c5SAndroid Build Coastguard Worker// * The buffer has pending writes in a commited render encoder 601*8975f5c5SAndroid Build Coastguard Worker// 602*8975f5c5SAndroid Build Coastguard Worker// In this case we're encoding commands that will happen after 603*8975f5c5SAndroid Build Coastguard Worker// that encoder 604*8975f5c5SAndroid Build Coastguard Worker// 605*8975f5c5SAndroid Build Coastguard Worker// safe = true 606*8975f5c5SAndroid Build Coastguard Worker// 607*8975f5c5SAndroid Build Coastguard Worker// * The buffer has pending writes in the current render encoder 608*8975f5c5SAndroid Build Coastguard Worker// 609*8975f5c5SAndroid Build Coastguard Worker// in this case we have to split/end the render encoder 610*8975f5c5SAndroid Build Coastguard Worker// before we can use the buffer. 611*8975f5c5SAndroid Build Coastguard Worker// 612*8975f5c5SAndroid Build Coastguard Worker// safe = false 613*8975f5c5SAndroid Build Coastguard Workerbool BufferMtl::isSafeToReadFromBufferViaBlit(ContextMtl *contextMtl) 614*8975f5c5SAndroid Build Coastguard Worker{ 615*8975f5c5SAndroid Build Coastguard Worker uint64_t serial = mBuffer->getLastWritingRenderEncoderSerial(); 616*8975f5c5SAndroid Build Coastguard Worker bool isSameSerial = contextMtl->isCurrentRenderEncoderSerial(serial); 617*8975f5c5SAndroid Build Coastguard Worker return !isSameSerial; 618*8975f5c5SAndroid Build Coastguard Worker} 619*8975f5c5SAndroid Build Coastguard Worker 620*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::updateExistingBufferViaBlitFromStagingBuffer(ContextMtl *contextMtl, 621*8975f5c5SAndroid Build Coastguard Worker const uint8_t *srcPtr, 622*8975f5c5SAndroid Build Coastguard Worker size_t sizeToCopy, 623*8975f5c5SAndroid Build Coastguard Worker size_t offset) 624*8975f5c5SAndroid Build Coastguard Worker{ 625*8975f5c5SAndroid Build Coastguard Worker ASSERT(isOffsetAndSizeMetalBlitCompatible(offset, sizeToCopy)); 626*8975f5c5SAndroid Build Coastguard Worker 627*8975f5c5SAndroid Build Coastguard Worker mtl::BufferManager &bufferManager = contextMtl->getBufferManager(); 628*8975f5c5SAndroid Build Coastguard Worker return bufferManager.queueBlitCopyDataToBuffer(contextMtl, srcPtr, sizeToCopy, offset, mBuffer); 629*8975f5c5SAndroid Build Coastguard Worker} 630*8975f5c5SAndroid Build Coastguard Worker 631*8975f5c5SAndroid Build Coastguard Worker// * get a new or unused buffer 632*8975f5c5SAndroid Build Coastguard Worker// * copy the new data to it 633*8975f5c5SAndroid Build Coastguard Worker// * copy any old data not overwriten by the new data to the new buffer 634*8975f5c5SAndroid Build Coastguard Worker// * start using the new buffer 635*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::putDataInNewBufferAndStartUsingNewBuffer(ContextMtl *contextMtl, 636*8975f5c5SAndroid Build Coastguard Worker const uint8_t *srcPtr, 637*8975f5c5SAndroid Build Coastguard Worker size_t sizeToCopy, 638*8975f5c5SAndroid Build Coastguard Worker size_t offset) 639*8975f5c5SAndroid Build Coastguard Worker{ 640*8975f5c5SAndroid Build Coastguard Worker ASSERT(isOffsetAndSizeMetalBlitCompatible(offset, sizeToCopy)); 641*8975f5c5SAndroid Build Coastguard Worker 642*8975f5c5SAndroid Build Coastguard Worker mtl::BufferRef oldBuffer = mBuffer; 643*8975f5c5SAndroid Build Coastguard Worker auto storageMode = mtl::Buffer::getStorageModeForUsage(contextMtl, mUsage); 644*8975f5c5SAndroid Build Coastguard Worker 645*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(allocateNewMetalBuffer(contextMtl, storageMode, mGLSize, 646*8975f5c5SAndroid Build Coastguard Worker /*returnOldBufferImmediately=*/false)); 647*8975f5c5SAndroid Build Coastguard Worker mBuffer->get().label = [NSString stringWithFormat:@"BufferMtl=%p(%lu)", this, ++mRevisionCount]; 648*8975f5c5SAndroid Build Coastguard Worker 649*8975f5c5SAndroid Build Coastguard Worker uint8_t *ptr = mBuffer->mapWithOpt(contextMtl, false, true); 650*8975f5c5SAndroid Build Coastguard Worker std::copy(srcPtr, srcPtr + sizeToCopy, ptr + offset); 651*8975f5c5SAndroid Build Coastguard Worker mBuffer->unmapAndFlushSubset(contextMtl, offset, sizeToCopy); 652*8975f5c5SAndroid Build Coastguard Worker 653*8975f5c5SAndroid Build Coastguard Worker if (offset > 0 || offset + sizeToCopy < mGLSize) 654*8975f5c5SAndroid Build Coastguard Worker { 655*8975f5c5SAndroid Build Coastguard Worker mtl::BlitCommandEncoder *blitEncoder = 656*8975f5c5SAndroid Build Coastguard Worker contextMtl->getBlitCommandEncoderWithoutEndingRenderEncoder(); 657*8975f5c5SAndroid Build Coastguard Worker if (offset > 0) 658*8975f5c5SAndroid Build Coastguard Worker { 659*8975f5c5SAndroid Build Coastguard Worker // copy old data before updated region 660*8975f5c5SAndroid Build Coastguard Worker blitEncoder->copyBuffer(oldBuffer, 0, mBuffer, 0, offset); 661*8975f5c5SAndroid Build Coastguard Worker } 662*8975f5c5SAndroid Build Coastguard Worker if (offset + sizeToCopy < mGLSize) 663*8975f5c5SAndroid Build Coastguard Worker { 664*8975f5c5SAndroid Build Coastguard Worker // copy old data after updated region 665*8975f5c5SAndroid Build Coastguard Worker const size_t endOffset = offset + sizeToCopy; 666*8975f5c5SAndroid Build Coastguard Worker const size_t endSizeToCopy = mGLSize - endOffset; 667*8975f5c5SAndroid Build Coastguard Worker blitEncoder->copyBuffer(oldBuffer, endOffset, mBuffer, endOffset, endSizeToCopy); 668*8975f5c5SAndroid Build Coastguard Worker } 669*8975f5c5SAndroid Build Coastguard Worker } 670*8975f5c5SAndroid Build Coastguard Worker 671*8975f5c5SAndroid Build Coastguard Worker mtl::BufferManager &bufferManager = contextMtl->getBufferManager(); 672*8975f5c5SAndroid Build Coastguard Worker bufferManager.returnBuffer(contextMtl, oldBuffer); 673*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 674*8975f5c5SAndroid Build Coastguard Worker} 675*8975f5c5SAndroid Build Coastguard Worker 676*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::copyDataToExistingBufferViaCPU(ContextMtl *contextMtl, 677*8975f5c5SAndroid Build Coastguard Worker const uint8_t *srcPtr, 678*8975f5c5SAndroid Build Coastguard Worker size_t sizeToCopy, 679*8975f5c5SAndroid Build Coastguard Worker size_t offset) 680*8975f5c5SAndroid Build Coastguard Worker{ 681*8975f5c5SAndroid Build Coastguard Worker uint8_t *ptr = mBuffer->map(contextMtl); 682*8975f5c5SAndroid Build Coastguard Worker std::copy(srcPtr, srcPtr + sizeToCopy, ptr + offset); 683*8975f5c5SAndroid Build Coastguard Worker mBuffer->unmapAndFlushSubset(contextMtl, offset, sizeToCopy); 684*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 685*8975f5c5SAndroid Build Coastguard Worker} 686*8975f5c5SAndroid Build Coastguard Worker 687*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::updateShadowCopyThenCopyShadowToNewBuffer(ContextMtl *contextMtl, 688*8975f5c5SAndroid Build Coastguard Worker const uint8_t *srcPtr, 689*8975f5c5SAndroid Build Coastguard Worker size_t sizeToCopy, 690*8975f5c5SAndroid Build Coastguard Worker size_t offset) 691*8975f5c5SAndroid Build Coastguard Worker{ 692*8975f5c5SAndroid Build Coastguard Worker // 1. Before copying data from client, we need to synchronize modified data from GPU to 693*8975f5c5SAndroid Build Coastguard Worker // shadow copy first. 694*8975f5c5SAndroid Build Coastguard Worker ensureShadowCopySyncedFromGPU(contextMtl); 695*8975f5c5SAndroid Build Coastguard Worker 696*8975f5c5SAndroid Build Coastguard Worker // 2. Copy data from client to shadow copy. 697*8975f5c5SAndroid Build Coastguard Worker std::copy(srcPtr, srcPtr + sizeToCopy, mShadowCopy.data() + offset); 698*8975f5c5SAndroid Build Coastguard Worker 699*8975f5c5SAndroid Build Coastguard Worker // 3. Copy data from shadow copy to GPU. 700*8975f5c5SAndroid Build Coastguard Worker return commitShadowCopy(contextMtl); 701*8975f5c5SAndroid Build Coastguard Worker} 702*8975f5c5SAndroid Build Coastguard Worker 703*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::setSubDataImpl(const gl::Context *context, 704*8975f5c5SAndroid Build Coastguard Worker const void *data, 705*8975f5c5SAndroid Build Coastguard Worker size_t size, 706*8975f5c5SAndroid Build Coastguard Worker size_t offset) 707*8975f5c5SAndroid Build Coastguard Worker{ 708*8975f5c5SAndroid Build Coastguard Worker if (!data) 709*8975f5c5SAndroid Build Coastguard Worker { 710*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 711*8975f5c5SAndroid Build Coastguard Worker } 712*8975f5c5SAndroid Build Coastguard Worker 713*8975f5c5SAndroid Build Coastguard Worker ASSERT(mBuffer); 714*8975f5c5SAndroid Build Coastguard Worker 715*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 716*8975f5c5SAndroid Build Coastguard Worker const angle::FeaturesMtl &features = contextMtl->getDisplay()->getFeatures(); 717*8975f5c5SAndroid Build Coastguard Worker 718*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_TRY(contextMtl, offset <= mGLSize); 719*8975f5c5SAndroid Build Coastguard Worker 720*8975f5c5SAndroid Build Coastguard Worker auto srcPtr = static_cast<const uint8_t *>(data); 721*8975f5c5SAndroid Build Coastguard Worker auto sizeToCopy = std::min<size_t>(size, mGLSize - offset); 722*8975f5c5SAndroid Build Coastguard Worker 723*8975f5c5SAndroid Build Coastguard Worker markConversionBuffersDirty(); 724*8975f5c5SAndroid Build Coastguard Worker 725*8975f5c5SAndroid Build Coastguard Worker if (features.preferCpuForBuffersubdata.enabled) 726*8975f5c5SAndroid Build Coastguard Worker { 727*8975f5c5SAndroid Build Coastguard Worker return copyDataToExistingBufferViaCPU(contextMtl, srcPtr, sizeToCopy, offset); 728*8975f5c5SAndroid Build Coastguard Worker } 729*8975f5c5SAndroid Build Coastguard Worker 730*8975f5c5SAndroid Build Coastguard Worker if (mShadowCopy.size() > 0) 731*8975f5c5SAndroid Build Coastguard Worker { 732*8975f5c5SAndroid Build Coastguard Worker return updateShadowCopyThenCopyShadowToNewBuffer(contextMtl, srcPtr, sizeToCopy, offset); 733*8975f5c5SAndroid Build Coastguard Worker } 734*8975f5c5SAndroid Build Coastguard Worker else 735*8975f5c5SAndroid Build Coastguard Worker { 736*8975f5c5SAndroid Build Coastguard Worker bool alwaysUseStagedBufferUpdates = features.alwaysUseStagedBufferUpdates.enabled; 737*8975f5c5SAndroid Build Coastguard Worker 738*8975f5c5SAndroid Build Coastguard Worker if (isOffsetAndSizeMetalBlitCompatible(offset, size) && 739*8975f5c5SAndroid Build Coastguard Worker (alwaysUseStagedBufferUpdates || mBuffer->isBeingUsedByGPU(contextMtl))) 740*8975f5c5SAndroid Build Coastguard Worker { 741*8975f5c5SAndroid Build Coastguard Worker if (alwaysUseStagedBufferUpdates || !isSafeToReadFromBufferViaBlit(contextMtl)) 742*8975f5c5SAndroid Build Coastguard Worker { 743*8975f5c5SAndroid Build Coastguard Worker // We can't use the buffer now so copy the data 744*8975f5c5SAndroid Build Coastguard Worker // to a staging buffer and blit it in 745*8975f5c5SAndroid Build Coastguard Worker return updateExistingBufferViaBlitFromStagingBuffer(contextMtl, srcPtr, sizeToCopy, 746*8975f5c5SAndroid Build Coastguard Worker offset); 747*8975f5c5SAndroid Build Coastguard Worker } 748*8975f5c5SAndroid Build Coastguard Worker else 749*8975f5c5SAndroid Build Coastguard Worker { 750*8975f5c5SAndroid Build Coastguard Worker return putDataInNewBufferAndStartUsingNewBuffer(contextMtl, srcPtr, sizeToCopy, 751*8975f5c5SAndroid Build Coastguard Worker offset); 752*8975f5c5SAndroid Build Coastguard Worker } 753*8975f5c5SAndroid Build Coastguard Worker } 754*8975f5c5SAndroid Build Coastguard Worker else 755*8975f5c5SAndroid Build Coastguard Worker { 756*8975f5c5SAndroid Build Coastguard Worker return copyDataToExistingBufferViaCPU(contextMtl, srcPtr, sizeToCopy, offset); 757*8975f5c5SAndroid Build Coastguard Worker } 758*8975f5c5SAndroid Build Coastguard Worker } 759*8975f5c5SAndroid Build Coastguard Worker} 760*8975f5c5SAndroid Build Coastguard Worker 761*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::commitShadowCopy(ContextMtl *contextMtl) 762*8975f5c5SAndroid Build Coastguard Worker{ 763*8975f5c5SAndroid Build Coastguard Worker return commitShadowCopy(contextMtl, mGLSize); 764*8975f5c5SAndroid Build Coastguard Worker} 765*8975f5c5SAndroid Build Coastguard Worker 766*8975f5c5SAndroid Build Coastguard Workerangle::Result BufferMtl::commitShadowCopy(ContextMtl *contextMtl, size_t size) 767*8975f5c5SAndroid Build Coastguard Worker{ 768*8975f5c5SAndroid Build Coastguard Worker auto storageMode = mtl::Buffer::getStorageModeForUsage(contextMtl, mUsage); 769*8975f5c5SAndroid Build Coastguard Worker 770*8975f5c5SAndroid Build Coastguard Worker size_t bufferSize = (mGLSize == 0 ? mShadowCopy.size() : mGLSize); 771*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(allocateNewMetalBuffer(contextMtl, storageMode, bufferSize, 772*8975f5c5SAndroid Build Coastguard Worker /*returnOldBufferImmediately=*/true)); 773*8975f5c5SAndroid Build Coastguard Worker 774*8975f5c5SAndroid Build Coastguard Worker if (size) 775*8975f5c5SAndroid Build Coastguard Worker { 776*8975f5c5SAndroid Build Coastguard Worker uint8_t *ptr = mBuffer->mapWithOpt(contextMtl, false, true); 777*8975f5c5SAndroid Build Coastguard Worker std::copy(mShadowCopy.data(), mShadowCopy.data() + size, ptr); 778*8975f5c5SAndroid Build Coastguard Worker mBuffer->unmapAndFlushSubset(contextMtl, 0, size); 779*8975f5c5SAndroid Build Coastguard Worker } 780*8975f5c5SAndroid Build Coastguard Worker 781*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 782*8975f5c5SAndroid Build Coastguard Worker} 783*8975f5c5SAndroid Build Coastguard Worker 784*8975f5c5SAndroid Build Coastguard Worker// SimpleWeakBufferHolderMtl implementation 785*8975f5c5SAndroid Build Coastguard WorkerSimpleWeakBufferHolderMtl::SimpleWeakBufferHolderMtl() 786*8975f5c5SAndroid Build Coastguard Worker{ 787*8975f5c5SAndroid Build Coastguard Worker mIsWeak = true; 788*8975f5c5SAndroid Build Coastguard Worker} 789*8975f5c5SAndroid Build Coastguard Worker 790*8975f5c5SAndroid Build Coastguard Worker} // namespace rx 791