#include "common.h" #include "declarations.h" #include "kernel/vc4_packet.h" //returns max index static uint32_t drawCommon(VkCommandBuffer commandBuffer, int32_t vertexOffset) { assert(commandBuffer); _commandBuffer* cb = commandBuffer; assert(((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->memGuard == 0xDDDDDDDD); //TODO handle cases when submitting >65k vertices in a VBO //TODO HW-2116 workaround //TODO GFXH-515 / SW-5891 workaround //TODO make this as lightweight as possible to make sure //as many drawcalls can be submitted as possible //uint32_t vertexBufferDirty; //uint32_t indexBufferDirty; ///uint32_t viewportDirty; ///uint32_t lineWidthDirty; ///uint32_t depthBiasDirty; ///uint32_t depthBoundsDirty; //uint32_t graphicsPipelineDirty; //uint32_t computePipelineDirty; //uint32_t subpassDirty; //uint32_t blendConstantsDirty; //uint32_t scissorDirty; //uint32_t stencilCompareMaskDirty; //uint32_t stencilWriteMaskDirty; //uint32_t stencilReferenceDirty; //uint32_t descriptorSetDirty; //uint32_t pushConstantDirty; static uint32_t drawCommon1; PROFILESTART(&drawCommon1); //TODO multiple viewports VkViewport vp; vp = cb->graphicsPipeline->viewports[0]; for(uint32_t c = 0; c < cb->graphicsPipeline->dynamicStateCount; ++c) { if(cb->graphicsPipeline->dynamicStates[c] == VK_DYNAMIC_STATE_VIEWPORT) { vp = cb->viewport; } } //if(cb->lineWidthDirty) { //Line width clFit(commandBuffer, &commandBuffer->binCl, V3D21_LINE_WIDTH_length); clInsertLineWidth(&commandBuffer->binCl, cb->graphicsPipeline->lineWidth); cb->lineWidthDirty = 0; } //if(cb->viewportDirty) { //Clip Window clFit(commandBuffer, &commandBuffer->binCl, V3D21_CLIP_WINDOW_length); clInsertClipWindow(&commandBuffer->binCl, vp.width, vp.height, vp.y, //bottom pixel coord vp.x); //left pixel coord //Vulkan conventions, Y flipped [1...-1] bottom->top //Clipper XY Scaling clFit(commandBuffer, &commandBuffer->binCl, V3D21_CLIPPER_XY_SCALING_length); clInsertClipperXYScaling(&commandBuffer->binCl, (float)(vp.width) * 0.5f * 16.0f, 1.0f * (float)(vp.height) * 0.5f * 16.0f); //Viewport Offset clFit(commandBuffer, &commandBuffer->binCl, V3D21_VIEWPORT_OFFSET_length); clInsertViewPortOffset(&commandBuffer->binCl, vp.width * 0.5f + vp.x, vp.height * 0.5f + vp.y); cb->viewportDirty = 0; } //if(cb->depthBiasDirty || cb->depthBoundsDirty) { //Configuration Bits clFit(commandBuffer, &commandBuffer->binCl, V3D21_CONFIGURATION_BITS_length); clInsertConfigurationBits(&commandBuffer->binCl, 1, //earlyz updates enable cb->graphicsPipeline->depthTestEnable, //earlyz enable cb->graphicsPipeline->depthWriteEnable && cb->graphicsPipeline->depthTestEnable, //z updates enable cb->graphicsPipeline->depthTestEnable ? getCompareOp(cb->graphicsPipeline->depthCompareOp) : V3D_COMPARE_FUNC_ALWAYS, //depth compare func 0, //coverage read mode 0, //coverage pipe select 0, //coverage update mode 0, //coverage read type cb->graphicsPipeline->rasterizationSamples > 1, //rasterizer oversample mode cb->graphicsPipeline->depthBiasEnable, //depth offset enable cb->graphicsPipeline->frontFace == VK_FRONT_FACE_CLOCKWISE, //clockwise !(cb->graphicsPipeline->cullMode & VK_CULL_MODE_BACK_BIT), //enable back facing primitives !(cb->graphicsPipeline->cullMode & VK_CULL_MODE_FRONT_BIT)); //enable front facing primitives clFit(commandBuffer, &commandBuffer->binCl, V3D21_DEPTH_OFFSET_length); float depthBiasConstant = cb->graphicsPipeline->depthBiasConstantFactor; float depthBiasSlope = cb->graphicsPipeline->depthBiasSlopeFactor; for(uint32_t c = 0; c < cb->graphicsPipeline->dynamicStateCount; ++c) { if(cb->graphicsPipeline->dynamicStates[c] == VK_DYNAMIC_STATE_DEPTH_BIAS) { depthBiasConstant = cb->depthBiasConstantFactor; depthBiasSlope = cb->depthBiasSlopeFactor; break; } } clInsertDepthOffset(&commandBuffer->binCl, depthBiasConstant, depthBiasSlope); //Vulkan conventions, we expect the resulting NDC space Z axis to be in range [0...1] close->far //cb->graphicsPipeline->minDepthBounds; //Clipper Z Scale and Offset clFit(commandBuffer, &commandBuffer->binCl, V3D21_CLIPPER_Z_SCALE_AND_OFFSET_length); //offset, scale float scale = vp.maxDepth - vp.minDepth; float offset = vp.minDepth; clInsertClipperZScaleOffset(&commandBuffer->binCl, offset, scale); cb->vertexBufferDirty = 0; cb->depthBoundsDirty = 0; } //Point size clFit(commandBuffer, &commandBuffer->binCl, V3D21_POINT_SIZE_length); clInsertPointSize(&commandBuffer->binCl, 1.0f); //TODO? //Flat Shade Flags clFit(commandBuffer, &commandBuffer->binCl, V3D21_FLAT_SHADE_FLAGS_length); clInsertFlatShadeFlags(&commandBuffer->binCl, 0); //GL Shader State clFit(commandBuffer, &commandBuffer->binCl, V3D21_GL_SHADER_STATE_length); clInsertShaderState(&commandBuffer->binCl, 0, //shader state record address 0, //extended shader state record cb->graphicsPipeline->vertexAttributeDescriptionCount & 0x7); //number of attribute arrays, 0 -> 8 _shaderModule* vertModule = 0, *fragModule = 0; //it could be that all stages are contained in a single module, or have separate modules if(cb->graphicsPipeline->modules[ulog2(VK_SHADER_STAGE_FRAGMENT_BIT)]) { fragModule = cb->graphicsPipeline->modules[ulog2(VK_SHADER_STAGE_FRAGMENT_BIT)]; } if(cb->graphicsPipeline->modules[ulog2(VK_SHADER_STAGE_VERTEX_BIT)]) { vertModule = cb->graphicsPipeline->modules[ulog2(VK_SHADER_STAGE_VERTEX_BIT)]; } if(!vertModule) { vertModule = fragModule; } if(!fragModule) { fragModule = vertModule; } assert(fragModule); assert(vertModule); assert(fragModule->bos[VK_RPI_ASSEMBLY_TYPE_FRAGMENT]); assert(vertModule->bos[VK_RPI_ASSEMBLY_TYPE_VERTEX]); assert(vertModule->bos[VK_RPI_ASSEMBLY_TYPE_COORDINATE]); PROFILEEND(&drawCommon1); static uint32_t drawCommon2; PROFILESTART(&drawCommon2); //emit shader record ControlListAddress fragCode = { .handle = fragModule->bos[VK_RPI_ASSEMBLY_TYPE_FRAGMENT], .offset = 0, }; ControlListAddress vertCode = { .handle = vertModule->bos[VK_RPI_ASSEMBLY_TYPE_VERTEX], .offset = 0, }; ControlListAddress coordCode = { .handle = vertModule->bos[VK_RPI_ASSEMBLY_TYPE_COORDINATE], .offset = 0, }; commandBuffer->shaderRecCount++; clFit(commandBuffer, &commandBuffer->shaderRecCl, 12 * sizeof(uint32_t) + 104 + 8 * 32); ControlList relocCl = commandBuffer->shaderRecCl; uint32_t attribCount = 0; uint32_t attribSelectBits = 0; for(uint32_t c = 0 ; c < cb->graphicsPipeline->vertexAttributeDescriptionCount; ++c) { if(cb->vertexBuffers[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding]) { attribCount++; attribSelectBits |= 1 << cb->graphicsPipeline->vertexAttributeDescriptions[c].location; } } //attrib size is simply how many times we read VPM (x4 bytes) in VS and CS //attrib records: //base address, num bytes, stride are for the kernel side to assemble our vpm //VPM offsets: these would be how many vpm reads were before a specific attrib (x4 bytes) //we don't really have that info, so we have to play with strides/formats uint32_t vertexAttribSize = 0, coordAttribSize = 0; for(uint32_t c = 0; c < cb->graphicsPipeline->vertexAttributeDescriptionCount; ++c) { vertexAttribSize += getFormatBpp(cb->graphicsPipeline->vertexAttributeDescriptions[c].format) >> 3; if(cb->graphicsPipeline->vertexAttributeDescriptions[c].location == 0) { //this should be the vertex coordinates location coordAttribSize = getFormatBpp(cb->graphicsPipeline->vertexAttributeDescriptions[c].format) >> 3; } } assert(vertModule->numVertVPMreads == vertexAttribSize >> 2); assert(vertModule->numCoordVPMreads == coordAttribSize >> 2); //number of attribs //3 is the number of type of possible shaders for(int c = 0; c < (3 + attribCount)*4; ++c) { clInsertNop(&commandBuffer->shaderRecCl); } clFit(commandBuffer, &commandBuffer->handlesCl, (3 + 8)*4); clInsertShaderRecord(&commandBuffer->shaderRecCl, &relocCl, &commandBuffer->handlesCl, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesBufOffset + cb->handlesCl.offset, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesSize, !fragModule->hasThreadSwitch, 0, //TODO point size included in shaded vertex data? 1, //enable clipping 0, //TODO fragment number of used uniforms? fragModule->numVaryings, //fragment number of varyings 0, //fragment uniform address? fragCode, //fragment code address 0, //TODO vertex number of used uniforms? attribSelectBits, //vertex attribute array select bits vertexAttribSize, //vertex total attribute size 0, //vertex uniform address vertCode, //vertex shader code address 0, //TODO coordinate number of used uniforms? //TODO how do we know which attribute contains the vertices? //for now the first one will be hardcoded to have the vertices... 1 << 0, //coordinate attribute array select bits coordAttribSize, //coordinate total attribute size 0, //coordinate uniform address coordCode //coordinate shader code address ); uint32_t vertexAttribOffsets[8] = {}; uint32_t coordAttribOffsets[8] = {}; for(uint32_t c = 1; c < 8; ++c) { for(uint32_t d = 0; d < cb->graphicsPipeline->vertexAttributeDescriptionCount; ++d) { if(cb->graphicsPipeline->vertexAttributeDescriptions[d].location < c) { vertexAttribOffsets[c] += getFormatBpp(cb->graphicsPipeline->vertexAttributeDescriptions[d].format) >> 3; } } } for(uint32_t c = 1; c < 8; ++c) { coordAttribOffsets[c] = vertexAttribOffsets[1]; } uint32_t maxIndex = 0xffff; for(uint32_t c = 0 ; c < cb->graphicsPipeline->vertexAttributeDescriptionCount; ++c) { if(cb->vertexBuffers[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding]) { uint32_t formatByteSize = getFormatBpp(cb->graphicsPipeline->vertexAttributeDescriptions[c].format) >> 3; uint32_t stride = cb->graphicsPipeline->vertexBindingDescriptions[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding].stride; if(stride > 0) { uint32_t usedIndices = (cb->vertexBuffers[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding]->boundMem->size - cb->graphicsPipeline->vertexAttributeDescriptions[c].offset - vertexOffset * stride - cb->vertexBufferOffsets[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding] - cb->vertexBuffers[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding]->boundOffset - formatByteSize) / stride; if(usedIndices < maxIndex) { maxIndex = usedIndices; } } ControlListAddress vertexBuffer = { .handle = cb->vertexBuffers[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding]->boundMem->bo, .offset = cb->graphicsPipeline->vertexAttributeDescriptions[c].offset + vertexOffset * stride + cb->vertexBufferOffsets[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding] + cb->vertexBuffers[cb->graphicsPipeline->vertexAttributeDescriptions[c].binding]->boundOffset, }; clInsertAttributeRecord(&commandBuffer->shaderRecCl, &relocCl, &commandBuffer->handlesCl, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesBufOffset + cb->handlesCl.offset, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesSize, vertexBuffer, //reloc address formatByteSize, stride, vertexAttribOffsets[cb->graphicsPipeline->vertexAttributeDescriptions[c].location], //vertex vpm offset coordAttribOffsets[cb->graphicsPipeline->vertexAttributeDescriptions[c].location] //coordinte vpm offset ); } } PROFILEEND(&drawCommon2); static uint32_t drawCommon3; PROFILESTART(&drawCommon3); //write uniforms _pipelineLayout* pl = cb->graphicsPipeline->layout; assert(vertModule->numVertVPMwrites - 3 == fragModule->numVaryings); assert(vertModule->numCoordVPMwrites == 7); uint32_t numTextureSamples = 0; uint32_t numFragUniformReads = 0; //kernel side expects relocations first! for(uint32_t c = 0; c < fragModule->numMappings[VK_RPI_ASSEMBLY_TYPE_FRAGMENT]; ++c) { VkRpiAssemblyMappingEXT mapping = fragModule->mappings[VK_RPI_ASSEMBLY_TYPE_FRAGMENT][c]; if(mapping.mappingType == VK_RPI_ASSEMBLY_MAPPING_TYPE_DESCRIPTOR) { numTextureSamples++; if(mapping.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || mapping.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || mapping.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { _descriptorSet* ds = getMapElement(pl->descriptorSetBindingMap, mapping.descriptorSet); _descriptorImage* di = getMapElement(ds->imageBindingMap, mapping.descriptorBinding); di += mapping.descriptorArrayElement; //emit reloc for texture BO clFit(commandBuffer, &commandBuffer->handlesCl, 4); uint32_t idx = clGetHandleIndex(&commandBuffer->handlesCl, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesBufOffset + cb->handlesCl.offset, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesSize, di->imageView->image->boundMem->bo); //emit tex bo reloc index clFit(commandBuffer, &commandBuffer->uniformsCl, 4); clInsertData(&commandBuffer->uniformsCl, 4, &idx); numFragUniformReads++; } else if(mapping.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || mapping.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || mapping.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || mapping.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) { _descriptorSet* ds = getMapElement(pl->descriptorSetBindingMap, mapping.descriptorSet); _descriptorBuffer* db = getMapElement(ds->bufferBindingMap, mapping.descriptorBinding); db += mapping.descriptorArrayElement; //emit reloc for BO clFit(commandBuffer, &commandBuffer->handlesCl, 4); uint32_t idx = clGetHandleIndex(&commandBuffer->handlesCl, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesBufOffset + cb->handlesCl.offset, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesSize, db->buffer->boundMem->bo); //emit bo reloc index clFit(commandBuffer, &commandBuffer->uniformsCl, 4); clInsertData(&commandBuffer->uniformsCl, 4, &idx); numFragUniformReads++; } else if(mapping.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || mapping.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) { _descriptorSet* ds = getMapElement(pl->descriptorSetBindingMap, mapping.descriptorSet); _descriptorTexelBuffer* dtb = getMapElement(ds->texelBufferBindingMap, mapping.descriptorBinding); dtb += mapping.descriptorArrayElement; //emit reloc for BO clFit(commandBuffer, &commandBuffer->handlesCl, 4); uint32_t idx = clGetHandleIndex(&commandBuffer->handlesCl, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesBufOffset + cb->handlesCl.offset, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesSize, dtb->bufferView->buffer->boundMem->bo); //emit bo reloc index clFit(commandBuffer, &commandBuffer->uniformsCl, 4); clInsertData(&commandBuffer->uniformsCl, 4, &idx); numFragUniformReads++; } else { assert(0); //shouldn't happen } } } assert(numTextureSamples == fragModule->numTextureSamples); //after relocs we can proceed with the usual uniforms for(uint32_t c = 0; c < fragModule->numMappings[VK_RPI_ASSEMBLY_TYPE_FRAGMENT]; ++c) { VkRpiAssemblyMappingEXT mapping = fragModule->mappings[VK_RPI_ASSEMBLY_TYPE_FRAGMENT][c]; if(mapping.mappingType == VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT) { numFragUniformReads++; clFit(commandBuffer, &commandBuffer->uniformsCl, 4); clInsertData(&commandBuffer->uniformsCl, 4, cb->pushConstantBufferPixel + mapping.resourceOffset); } else if(mapping.mappingType == VK_RPI_ASSEMBLY_MAPPING_TYPE_DESCRIPTOR) { if(mapping.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || mapping.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || mapping.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) { _descriptorSet* ds = getMapElement(pl->descriptorSetBindingMap, mapping.descriptorSet); _descriptorImage* di = getMapElement(ds->imageBindingMap, mapping.descriptorBinding); di += mapping.descriptorArrayElement; uint32_t cubemapStride = (di->imageView->image->width * di->imageView->image->height * getFormatBpp(di->imageView->interpretedFormat)) >> 3; //fprintf(stderr, "cubemap stride %i\n", cubemapStride); uint32_t numLevels = 0; numLevels = di->imageView->subresourceRange.levelCount < di->imageView->image->miplevels ? di->imageView->subresourceRange.levelCount : di->imageView->image->miplevels; uint32_t params[4]; encodeTextureUniform(params, numLevels - 1, getTextureDataType(di->imageView->interpretedFormat), di->imageView->viewType == VK_IMAGE_VIEW_TYPE_CUBE, cubemapStride >> 12, //cubemap stride in multiples of 4KB (di->imageView->image->levelOffsets[0] + di->imageView->image->boundOffset) >> 12, //Image level 0 offset in multiples of 4KB di->imageView->image->height & 2047, di->imageView->image->width & 2047, getMinFilterType(di->sampler->minFilter, di->sampler->mipmapMode),// di->sampler->maxLod), di->sampler->magFilter == VK_FILTER_NEAREST, getWrapMode(di->sampler->addressModeU), getWrapMode(di->sampler->addressModeV), di->sampler->disableAutoLod ); uint32_t size = 0; if(di->imageView->viewType == VK_IMAGE_VIEW_TYPE_1D) { size = 4; } else if(di->imageView->viewType == VK_IMAGE_VIEW_TYPE_2D) { size = 8; } else if(di->imageView->viewType == VK_IMAGE_VIEW_TYPE_CUBE) { size = 12; } else { assert(0); //unsupported } //TMU0_B requires an extra uniform written //we need to signal that somehow from API side //if mode is cubemap we don't need an extra uniform, it's included! if(di->imageView->viewType != VK_IMAGE_VIEW_TYPE_CUBE && di->sampler->disableAutoLod) { size += 4; } numFragUniformReads += size >> 2; //emit tex parameters clFit(commandBuffer, &commandBuffer->uniformsCl, size); clInsertData(&commandBuffer->uniformsCl, size, params); } } } assert(numFragUniformReads == fragModule->numFragUniformReads); PROFILEEND(&drawCommon3); static uint32_t drawCommon4; PROFILESTART(&drawCommon4); uint32_t numVertUniformReads = 0; //vertex and then coordinate for(uint32_t c = 0; c < vertModule->numMappings[VK_RPI_ASSEMBLY_TYPE_VERTEX]; ++c) { VkRpiAssemblyMappingEXT mapping = vertModule->mappings[VK_RPI_ASSEMBLY_TYPE_VERTEX][c]; if(mapping.mappingType == VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT) { numVertUniformReads++; clFit(commandBuffer, &commandBuffer->uniformsCl, 4); clInsertData(&commandBuffer->uniformsCl, 4, cb->pushConstantBufferVertex + mapping.resourceOffset); } else if(mapping.mappingType == VK_RPI_ASSEMBLY_MAPPING_TYPE_DESCRIPTOR) { } else { assert(0); //shouldn't happen } } assert(numVertUniformReads == vertModule->numVertUniformReads); uint32_t numCoordUniformReads = 0; //if there are no coordinate mappings, just use the vertex ones VkRpiAssemblyTypeEXT coordMappingType = VK_RPI_ASSEMBLY_TYPE_COORDINATE; if(vertModule->numMappings[VK_RPI_ASSEMBLY_TYPE_COORDINATE] < 1) { coordMappingType = VK_RPI_ASSEMBLY_TYPE_VERTEX; } for(uint32_t c = 0; c < vertModule->numMappings[coordMappingType]; ++c) { VkRpiAssemblyMappingEXT mapping = vertModule->mappings[coordMappingType][c]; if(mapping.mappingType == VK_RPI_ASSEMBLY_MAPPING_TYPE_PUSH_CONSTANT) { numCoordUniformReads++; clFit(commandBuffer, &commandBuffer->uniformsCl, 4); clInsertData(&commandBuffer->uniformsCl, 4, cb->pushConstantBufferVertex + mapping.resourceOffset); } else if(mapping.mappingType == VK_RPI_ASSEMBLY_MAPPING_TYPE_DESCRIPTOR) { } else { assert(0); //shouldn't happen } } assert(numCoordUniformReads == vertModule->numCoordUniformReads); PROFILEEND(&drawCommon4); return maxIndex; } /* * https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkCmdDraw */ void RPIFUNC(vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) { PROFILESTART(RPIFUNC(vkCmdDraw)); assert(commandBuffer); if(instanceCount != 1 || firstInstance != 0) { unsigned instancing; UNSUPPORTED(instancing); } drawCommon(commandBuffer, 0); _commandBuffer* cb = commandBuffer; //Submit draw call: vertex Array Primitives clFit(commandBuffer, &commandBuffer->binCl, V3D21_VERTEX_ARRAY_PRIMITIVES_length); clInsertVertexArrayPrimitives(&commandBuffer->binCl, firstVertex, vertexCount, getPrimitiveMode(cb->graphicsPipeline->topology)); cb->numDrawCallsSubmitted++; PROFILEEND(RPIFUNC(vkCmdDraw)); } VKAPI_ATTR void VKAPI_CALL RPIFUNC(vkCmdDrawIndexed)( VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { PROFILESTART(RPIFUNC(vkCmdDrawIndexed)); assert(commandBuffer); if(instanceCount != 1 || firstInstance != 0) { unsigned instancing; UNSUPPORTED(instancing); } uint32_t maxIndex = drawCommon(commandBuffer, vertexOffset); _commandBuffer* cb = commandBuffer; clFit(commandBuffer, &commandBuffer->handlesCl, 4); uint32_t idx = clGetHandleIndex(&commandBuffer->handlesCl, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesBufOffset + cb->handlesCl.offset, ((CLMarker*)getCPAptrFromOffset(cb->binCl.CPA, cb->binCl.currMarkerOffset))->handlesSize, cb->indexBuffer->boundMem->bo); clInsertGEMRelocations(&commandBuffer->binCl, idx, 0); //Submit draw call: vertex Array Primitives clFit(commandBuffer, &commandBuffer->binCl, V3D21_VERTEX_ARRAY_PRIMITIVES_length); clInsertIndexedPrimitiveList(&commandBuffer->binCl, maxIndex, //max index cb->indexBuffer->boundOffset + cb->indexBufferOffset + firstIndex * 2, indexCount, 1, //we only support 16 bit indices getPrimitiveMode(cb->graphicsPipeline->topology)); cb->numDrawCallsSubmitted++; PROFILEEND(RPIFUNC(vkCmdDrawIndexed)); } VKAPI_ATTR void VKAPI_CALL RPIFUNC(vkCmdDrawIndexedIndirect)( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) { UNSUPPORTED(vkCmdDrawIndexedIndirect); } VKAPI_ATTR void VKAPI_CALL RPIFUNC(vkCmdDrawIndirect)( VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) { UNSUPPORTED(vkCmdDrawIndirect); }