1// 2// Copyright 2020 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6// TransformFeedbackMtl.mm: 7// Defines the class interface for TransformFeedbackMtl, implementing TransformFeedbackImpl. 8// 9 10#include "libANGLE/renderer/metal/TransformFeedbackMtl.h" 11 12#include "common/debug.h" 13#include "libANGLE/Context.h" 14#include "libANGLE/Query.h" 15#include "libANGLE/renderer/metal/ContextMtl.h" 16#include "libANGLE/renderer/metal/QueryMtl.h" 17 18namespace rx 19{ 20 21TransformFeedbackMtl::TransformFeedbackMtl(const gl::TransformFeedbackState &state) 22 : TransformFeedbackImpl(state) 23{} 24 25TransformFeedbackMtl::~TransformFeedbackMtl() {} 26 27angle::Result TransformFeedbackMtl::begin(const gl::Context *context, 28 gl::PrimitiveMode primitiveMode) 29{ 30 mtl::GetImpl(context)->onTransformFeedbackActive(context, this); 31 32 return angle::Result::Continue; 33} 34 35angle::Result TransformFeedbackMtl::end(const gl::Context *context) 36{ 37 const gl::State &glState = context->getState(); 38 gl::Query *transformFeedbackQuery = 39 glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten); 40 if (transformFeedbackQuery) 41 { 42 mtl::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(context); 43 } 44 45 mtl::GetImpl(context)->onTransformFeedbackInactive(context, this); 46 47 return angle::Result::Continue; 48} 49 50angle::Result TransformFeedbackMtl::pause(const gl::Context *context) 51{ 52 // When XFB is paused, OpenGL allows XFB buffers to be bound for other purposes. We need to call 53 // onTransformFeedbackInactive() to issue a sync. 54 mtl::GetImpl(context)->onTransformFeedbackInactive(context, this); 55 56 return angle::Result::Continue; 57} 58 59angle::Result TransformFeedbackMtl::resume(const gl::Context *context) 60{ 61 mtl::GetImpl(context)->onTransformFeedbackActive(context, this); 62 63 return angle::Result::Continue; 64} 65 66angle::Result TransformFeedbackMtl::bindIndexedBuffer( 67 const gl::Context *context, 68 size_t index, 69 const gl::OffsetBindingPointer<gl::Buffer> &binding) 70{ 71 // Do nothing for now 72 73 return angle::Result::Continue; 74} 75 76angle::Result TransformFeedbackMtl::getBufferOffsets(ContextMtl *contextMtl, 77 GLint drawCallFirstVertex, 78 uint32_t skippedVertices, 79 int32_t *offsetsOut) 80{ 81 int64_t verticesDrawn = static_cast<int64_t>(mState.getVerticesDrawn()) + skippedVertices; 82 const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable(); 83 ASSERT(executable); 84 const std::vector<GLsizei> &bufferStrides = executable->getTransformFeedbackStrides(); 85 size_t xfbBufferCount = executable->getTransformFeedbackBufferCount(); 86 87 ASSERT(xfbBufferCount > 0); 88 89 for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex) 90 { 91 const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = 92 mState.getIndexedBuffer(bufferIndex); 93 94 ASSERT((bufferBinding.getOffset() % 4) == 0); 95 96 // Offset the gl_VertexIndex by drawCallFirstVertex 97 int64_t drawCallVertexOffset = static_cast<int64_t>(verticesDrawn) - drawCallFirstVertex; 98 99 int64_t writeOffset = 100 (bufferBinding.getOffset() + drawCallVertexOffset * bufferStrides[bufferIndex]) / 101 static_cast<int64_t>(sizeof(uint32_t)); 102 103 offsetsOut[bufferIndex] = static_cast<int32_t>(writeOffset); 104 105 // Check for overflow. 106 ANGLE_CHECK_GL_ALLOC(contextMtl, offsetsOut[bufferIndex] == writeOffset); 107 } 108 109 return angle::Result::Continue; 110} 111 112} // namespace rx 113