blob: 5b2d6304d10a64d59ee5e9ae7c209b82d417bffc [file] [log] [blame]
/*
* MVKCmdDraw.mm
*
* Copyright (c) 2014-2018 The Brenwill Workshop Ltd. (http://www.brenwill.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MVKCmdDraw.h"
#include "MVKCommandBuffer.h"
#include "MVKCommandPool.h"
#include "MVKBuffer.h"
#include "MVKFoundation.h"
#include "mvk_datatypes.h"
#pragma mark -
#pragma mark MVKCmdBindVertexBuffers
void MVKCmdBindVertexBuffers::setContent(uint32_t startBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets) {
_bindings.clear(); // Clear for reuse
_bindings.reserve(bindingCount);
MVKMTLBufferBinding b;
for (uint32_t bindIdx = 0; bindIdx < bindingCount; bindIdx++) {
MVKBuffer* mvkBuffer = (MVKBuffer*)pBuffers[bindIdx];
b.index = getDevice()->getMetalBufferIndexForVertexAttributeBinding(startBinding + bindIdx);
b.mtlBuffer = mvkBuffer->getMTLBuffer();
b.offset = mvkBuffer->getMTLBufferOffset() + pOffsets[bindIdx];
_bindings.push_back(b);
}
}
void MVKCmdBindVertexBuffers::encode(MVKCommandEncoder* cmdEncoder) {
for (auto& b : _bindings) { cmdEncoder->_graphicsResourcesState.bindVertexBuffer(b); }
}
MVKCmdBindVertexBuffers::MVKCmdBindVertexBuffers(MVKCommandTypePool<MVKCmdBindVertexBuffers>* pool)
: MVKCommand::MVKCommand((MVKCommandTypePool<MVKCommand>*)pool) {}
#pragma mark -
#pragma mark MVKCmdBindIndexBuffer
void MVKCmdBindIndexBuffer::setContent(VkBuffer buffer,
VkDeviceSize offset,
VkIndexType indexType) {
MVKBuffer* mvkBuffer = (MVKBuffer*)buffer;
_binding.mtlBuffer = mvkBuffer->getMTLBuffer();
_binding.offset = mvkBuffer->getMTLBufferOffset() + offset;
_binding.mtlIndexType = mvkMTLIndexTypeFromVkIndexType(indexType);
}
void MVKCmdBindIndexBuffer::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_graphicsResourcesState.bindIndexBuffer(_binding);
}
MVKCmdBindIndexBuffer::MVKCmdBindIndexBuffer(MVKCommandTypePool<MVKCmdBindIndexBuffer>* pool)
: MVKCommand::MVKCommand((MVKCommandTypePool<MVKCommand>*)pool) {}
#pragma mark -
#pragma mark MVKCmdDraw
void MVKCmdDraw::setContent(uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance) {
_vertexCount = vertexCount;
_instanceCount = instanceCount;
_firstVertex = firstVertex;
_firstInstance = firstInstance;
// Validate
clearConfigurationResult();
if ((_firstInstance != 0) && !(getDevice()->_pMetalFeatures->baseVertexInstanceDrawing)) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdDraw(): The current device does not support drawing with a non-zero base instance."));
}
}
void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->finalizeDrawState(); // Ensure all updated state has been submitted to Metal
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
vertexStart: _firstVertex
vertexCount: _vertexCount
instanceCount: _instanceCount
baseInstance: _firstInstance];
} else {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
vertexStart: _firstVertex
vertexCount: _vertexCount
instanceCount: _instanceCount];
}
}
MVKCmdDraw::MVKCmdDraw(MVKCommandTypePool<MVKCmdDraw>* pool)
: MVKCommand::MVKCommand((MVKCommandTypePool<MVKCommand>*)pool) {
}
#pragma mark -
#pragma mark MVKCmdDrawIndexed
void MVKCmdDrawIndexed::setContent(uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
int32_t vertexOffset,
uint32_t firstInstance) {
_indexCount = indexCount;
_instanceCount = instanceCount;
_firstIndex = firstIndex;
_vertexOffset = vertexOffset;
_firstInstance = firstInstance;
// Validate
clearConfigurationResult();
if ((_firstInstance != 0) && !(getDevice()->_pMetalFeatures->baseVertexInstanceDrawing)) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdDrawIndexed(): The current device does not support drawing with a non-zero base instance."));
}
if ((_vertexOffset != 0) && !(getDevice()->_pMetalFeatures->baseVertexInstanceDrawing)) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdDrawIndexed(): The current device does not support drawing with a non-zero base vertex."));
}
}
void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->finalizeDrawState(); // Ensure all updated state has been submitted to Metal
MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding;
size_t idxSize = mvkMTLIndexTypeSizeInBytes(ibb.mtlIndexType);
VkDeviceSize idxBuffOffset = ibb.offset + (_firstIndex * idxSize);
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
indexCount: _indexCount
indexType: ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer
indexBufferOffset: idxBuffOffset
instanceCount: _instanceCount
baseVertex: _vertexOffset
baseInstance: _firstInstance];
} else {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
indexCount: _indexCount
indexType: ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer
indexBufferOffset: idxBuffOffset
instanceCount: _instanceCount];
}
}
MVKCmdDrawIndexed::MVKCmdDrawIndexed(MVKCommandTypePool<MVKCmdDrawIndexed>* pool)
: MVKCommand::MVKCommand((MVKCommandTypePool<MVKCommand>*)pool) {}
#pragma mark -
#pragma mark MVKCmdDrawIndirect
void MVKCmdDrawIndirect::setContent(VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride) {
MVKBuffer* mvkBuffer = (MVKBuffer*)buffer;
_mtlIndirectBuffer = mvkBuffer->getMTLBuffer();
_mtlIndirectBufferOffset = mvkBuffer->getMTLBufferOffset() + offset;
_mtlIndirectBufferStride = stride;
_drawCount = drawCount;
// Validate
clearConfigurationResult();
if ( !(getDevice()->_pMetalFeatures->indirectDrawing) ) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdDrawIndirect(): The current device does not support indirect drawing."));
}
}
void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->finalizeDrawState(); // Ensure all updated state has been submitted to Metal
VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
for (uint32_t drawIdx = 0; drawIdx < _drawCount; drawIdx++) {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
indirectBuffer: _mtlIndirectBuffer
indirectBufferOffset: mtlIndBuffOfst];
mtlIndBuffOfst += _mtlIndirectBufferStride;
}
}
MVKCmdDrawIndirect::MVKCmdDrawIndirect(MVKCommandTypePool<MVKCmdDrawIndirect>* pool)
: MVKCommand::MVKCommand((MVKCommandTypePool<MVKCommand>*)pool) {}
#pragma mark -
#pragma mark MVKCmdDrawIndexedIndirect
void MVKCmdDrawIndexedIndirect::setContent(VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride) {
MVKBuffer* mvkBuffer = (MVKBuffer*)buffer;
_mtlIndirectBuffer = mvkBuffer->getMTLBuffer();
_mtlIndirectBufferOffset = mvkBuffer->getMTLBufferOffset() + offset;
_mtlIndirectBufferStride = stride;
_drawCount = drawCount;
// Validate
clearConfigurationResult();
if ( !(getDevice()->_pMetalFeatures->indirectDrawing) ) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdDrawIndexedIndirect(): The current device does not support indirect drawing."));
}
}
void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->finalizeDrawState(); // Ensure all updated state has been submitted to Metal
MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding;
VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
for (uint32_t drawIdx = 0; drawIdx < _drawCount; drawIdx++) {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
indexType: ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer
indexBufferOffset: ibb.offset
indirectBuffer: _mtlIndirectBuffer
indirectBufferOffset: mtlIndBuffOfst];
mtlIndBuffOfst += _mtlIndirectBufferStride;
}
}
MVKCmdDrawIndexedIndirect::MVKCmdDrawIndexedIndirect(MVKCommandTypePool<MVKCmdDrawIndexedIndirect>* pool)
: MVKCommand::MVKCommand((MVKCommandTypePool<MVKCommand>*)pool) {}
#pragma mark -
#pragma mark Command creation functions
void mvkCmdBindVertexBuffers(MVKCommandBuffer* cmdBuff,
uint32_t startBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets) {
MVKCmdBindVertexBuffers* cmd = cmdBuff->_commandPool->_cmdBindVertexBuffersPool.acquireObject();
cmd->setContent(startBinding, bindingCount, pBuffers, pOffsets);
cmdBuff->addCommand(cmd);
}
void mvkCmdDraw(MVKCommandBuffer* cmdBuff,
uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance) {
MVKCmdDraw* cmd = cmdBuff->_commandPool->_cmdDrawPool.acquireObject();
cmd->setContent(vertexCount, instanceCount, firstVertex, firstInstance);
cmdBuff->addCommand(cmd);
}
void mvkCmdDrawIndexed(MVKCommandBuffer* cmdBuff,
uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
int32_t vertexOffset,
uint32_t firstInstance) {
MVKCmdDrawIndexed* cmd = cmdBuff->_commandPool->_cmdDrawIndexedPool.acquireObject();
cmd->setContent(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
cmdBuff->addCommand(cmd);
}
void mvkCmdBindIndexBuffer(MVKCommandBuffer* cmdBuff,
VkBuffer buffer,
VkDeviceSize offset,
VkIndexType indexType) {
MVKCmdBindIndexBuffer* cmd = cmdBuff->_commandPool->_cmdBindIndexBufferPool.acquireObject();
cmd->setContent(buffer, offset, indexType);
cmdBuff->addCommand(cmd);
}
void mvkCmdDrawIndirect(MVKCommandBuffer* cmdBuff,
VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride) {
MVKCmdDrawIndirect* cmd = cmdBuff->_commandPool->_cmdDrawIndirectPool.acquireObject();
cmd->setContent(buffer, offset, drawCount, stride);
cmdBuff->addCommand(cmd);
}
void mvkCmdDrawIndexedIndirect(MVKCommandBuffer* cmdBuff,
VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride) {
MVKCmdDrawIndexedIndirect* cmd = cmdBuff->_commandPool->_cmdDrawIndexedIndirectPool.acquireObject();
cmd->setContent(buffer, offset, drawCount, stride);
cmdBuff->addCommand(cmd);
}