for(int i = 0; i < MAX_VERTEX_INPUTS; i++)
{
data->input[i] = context->input[i].buffer;
- data->stride[i] = context->input[i].stride;
+ data->stride[i] = context->input[i].vertexStride;
}
if(context->indexBuffer)
data->indices = context->indexBuffer;
}
- if(context->vertexShader->hasBuiltinInput(spv::BuiltInInstanceId))
+ if(context->vertexShader->hasBuiltinInput(spv::BuiltInInstanceIndex))
{
data->instanceID = context->instanceID;
}
queries.remove(query);
}
+ void Renderer::advanceInstanceAttributes()
+ {
+ for(uint32_t i = 0; i < vk::MAX_VERTEX_INPUT_BINDINGS; i++)
+ {
+ auto &attrib = context->input[i];
+ if (attrib.count && attrib.instanceStride)
+ {
+ // Under the casts: attrib.buffer += attrib.instanceStride
+ attrib.buffer = (void const *)((uintptr_t)attrib.buffer + attrib.instanceStride);
+ }
+ }
+ }
+
#if PERF_HUD
int Renderer::getThreadCount()
{
void addQuery(Query *query);
void removeQuery(Query *query);
+ void advanceInstanceAttributes();
+
void synchronize();
#if PERF_HUD
struct StreamResource
{
const void *buffer;
- unsigned int stride;
+ unsigned int vertexStride;
+ unsigned int instanceStride;
};
struct Stream : public StreamResource
{
- Stream(const void *buffer = nullptr, unsigned int stride = 0)
+ Stream(const void *buffer = nullptr, unsigned int vertexStride = 0)
{
this->buffer = buffer;
- this->stride = stride;
+ this->vertexStride = vertexStride;
+ this->instanceStride = 0;
}
Stream &define(StreamType type, unsigned int count, bool normalized = false)
static const float4 null = {0, 0, 0, 1};
buffer = &null;
- stride = 0;
+ vertexStride = 0;
+ instanceStride = 0;
type = STREAMTYPE_FLOAT;
count = 0;
normalized = false;
const VkIndexType indexType;
};
-void CommandBuffer::ExecutionState::bindVertexInputs(sw::Context& context, int firstVertex)
+void CommandBuffer::ExecutionState::bindVertexInputs(sw::Context& context, int firstVertex, int firstInstance)
{
for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
{
const auto &vertexInput = vertexInputBindings[attrib.binding];
Buffer *buffer = Cast(vertexInput.buffer);
attrib.buffer = buffer ? buffer->getOffsetPointer(
- attrib.offset + vertexInput.offset + attrib.stride * firstVertex) : nullptr;
+ attrib.offset + vertexInput.offset + attrib.vertexStride * firstVertex + attrib.instanceStride * firstInstance) : nullptr;
}
}
}
executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS]);
sw::Context context = pipeline->getContext();
- executionState.bindVertexInputs(context, firstVertex);
+ executionState.bindVertexInputs(context, firstVertex, firstInstance);
const auto& boundDescriptorSets = executionState.boundDescriptorSets[VK_PIPELINE_BIND_POINT_GRAPHICS];
for(int i = 0; i < vk::MAX_BOUND_DESCRIPTOR_SETS; i++)
executionState.bindAttachments();
const uint32_t primitiveCount = pipeline->computePrimitiveCount(vertexCount);
- const uint32_t lastInstance = firstInstance + instanceCount - 1;
- for(uint32_t instance = firstInstance; instance <= lastInstance; instance++)
+ for(uint32_t instance = firstInstance; instance != firstInstance + instanceCount; instance++)
{
executionState.renderer->setInstanceID(instance);
executionState.renderer->draw(context.drawType, primitiveCount);
+ executionState.renderer->advanceInstanceAttributes();
}
}
executionState.pipelines[VK_PIPELINE_BIND_POINT_GRAPHICS]);
sw::Context context = pipeline->getContext();
- executionState.bindVertexInputs(context, vertexOffset);
+
+ executionState.bindVertexInputs(context, vertexOffset, firstInstance);
const auto& boundDescriptorSets = executionState.boundDescriptorSets[VK_PIPELINE_BIND_POINT_GRAPHICS];
for(int i = 0; i < vk::MAX_BOUND_DESCRIPTOR_SETS; i++)
? (context.drawType | sw::DRAW_INDEXED16) : (context.drawType | sw::DRAW_INDEXED32);
const uint32_t primitiveCount = pipeline->computePrimitiveCount(indexCount);
- const uint32_t lastInstance = firstInstance + instanceCount - 1;
- for(uint32_t instance = firstInstance; instance <= lastInstance; instance++)
+ for(uint32_t instance = firstInstance; instance != firstInstance + instanceCount; instance++)
{
executionState.renderer->setInstanceID(instance);
executionState.renderer->draw(static_cast<sw::DrawType>(drawType), primitiveCount);
+ executionState.renderer->advanceInstanceAttributes();
}
}
VkIndexType indexType;
void bindAttachments();
- void bindVertexInputs(sw::Context& context, int firstVertex);
+ void bindVertexInputs(sw::Context& context, int firstVertex, int firstInstance);
};
void submit(CommandBuffer::ExecutionState& executionState);
// Temporary in-binding-order representation of buffer strides, to be consumed below
// when considering attributes. TODO: unfuse buffers from attributes in backend, is old GL model.
- uint32_t bufferStrides[MAX_VERTEX_INPUT_BINDINGS];
+ uint32_t vertexStrides[MAX_VERTEX_INPUT_BINDINGS];
+ uint32_t instanceStrides[MAX_VERTEX_INPUT_BINDINGS];
for(uint32_t i = 0; i < vertexInputState->vertexBindingDescriptionCount; i++)
{
auto const & desc = vertexInputState->pVertexBindingDescriptions[i];
- bufferStrides[desc.binding] = desc.stride;
- if(desc.inputRate != VK_VERTEX_INPUT_RATE_VERTEX)
- {
- UNIMPLEMENTED("vertexInputState->pVertexBindingDescriptions[%d]", i);
- }
+ vertexStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_VERTEX ? desc.stride : 0;
+ instanceStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE ? desc.stride : 0;
}
for(uint32_t i = 0; i < vertexInputState->vertexAttributeDescriptionCount; i++)
input.normalized = !vk::Format(desc.format).isNonNormalizedInteger();
input.offset = desc.offset;
input.binding = desc.binding;
- input.stride = bufferStrides[desc.binding];
+ input.vertexStride = vertexStrides[desc.binding];
+ input.instanceStride = instanceStrides[desc.binding];
}
const VkPipelineInputAssemblyStateCreateInfo* assemblyState = pCreateInfo->pInputAssemblyState;