// // Copyright 2020 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // TransformFeedbackMtl.mm: // Defines the class interface for TransformFeedbackMtl, implementing TransformFeedbackImpl. // #include "libANGLE/renderer/metal/TransformFeedbackMtl.h" #include "common/debug.h" #include "libANGLE/Context.h" #include "libANGLE/Query.h" #include "libANGLE/renderer/metal/ContextMtl.h" #include "libANGLE/renderer/metal/QueryMtl.h" namespace rx { TransformFeedbackMtl::TransformFeedbackMtl(const gl::TransformFeedbackState &state) : TransformFeedbackImpl(state) {} TransformFeedbackMtl::~TransformFeedbackMtl() {} angle::Result TransformFeedbackMtl::begin(const gl::Context *context, gl::PrimitiveMode primitiveMode) { mtl::GetImpl(context)->onTransformFeedbackActive(context, this); return angle::Result::Continue; } angle::Result TransformFeedbackMtl::end(const gl::Context *context) { const gl::State &glState = context->getState(); gl::Query *transformFeedbackQuery = glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten); if (transformFeedbackQuery) { mtl::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(context); } mtl::GetImpl(context)->onTransformFeedbackInactive(context, this); return angle::Result::Continue; } angle::Result TransformFeedbackMtl::pause(const gl::Context *context) { // When XFB is paused, OpenGL allows XFB buffers to be bound for other purposes. We need to call // onTransformFeedbackInactive() to issue a sync. mtl::GetImpl(context)->onTransformFeedbackInactive(context, this); return angle::Result::Continue; } angle::Result TransformFeedbackMtl::resume(const gl::Context *context) { mtl::GetImpl(context)->onTransformFeedbackActive(context, this); return angle::Result::Continue; } angle::Result TransformFeedbackMtl::bindIndexedBuffer( const gl::Context *context, size_t index, const gl::OffsetBindingPointer &binding) { // Do nothing for now return angle::Result::Continue; } angle::Result TransformFeedbackMtl::getBufferOffsets(ContextMtl *contextMtl, GLint drawCallFirstVertex, uint32_t skippedVertices, int32_t *offsetsOut) { int64_t verticesDrawn = static_cast(mState.getVerticesDrawn()) + skippedVertices; const std::vector &bufferStrides = mState.getBoundProgram()->getTransformFeedbackStrides(); const gl::ProgramExecutable *executable = contextMtl->getState().getProgramExecutable(); ASSERT(executable); size_t xfbBufferCount = executable->getTransformFeedbackBufferCount(); ASSERT(xfbBufferCount > 0); for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex) { const gl::OffsetBindingPointer &bufferBinding = mState.getIndexedBuffer(bufferIndex); ASSERT((bufferBinding.getOffset() % 4) == 0); // Offset the gl_VertexIndex by drawCallFirstVertex int64_t drawCallVertexOffset = static_cast(verticesDrawn) - drawCallFirstVertex; int64_t writeOffset = (bufferBinding.getOffset() + drawCallVertexOffset * bufferStrides[bufferIndex]) / static_cast(sizeof(uint32_t)); offsetsOut[bufferIndex] = static_cast(writeOffset); // Check for overflow. ANGLE_CHECK_GL_ALLOC(contextMtl, offsetsOut[bufferIndex] == writeOffset); } return angle::Result::Continue; } } // namespace rx