xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/BufferMtl.mm (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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