uint32_t endUserCommandBuffer(uint32_t *buffer) { auto core = coreinit::OSGetCoreId(); auto &cb = sActiveBuffer[core]; decaf_check(cb); decaf_check(cb->displayList); if (buffer != cb->buffer) { // HACK: FAST Racing Neo shows this behaviour, gx2.rpl seems to not really care about what pointer // you pass into GX2EndDisplayList, so it's possible this is perfectly valid behaviour and the error // an application one, and not one caused by us. gLog->warn("Display list passed to GX2EndDisplayList did not match one passed to GX2BeginDisplayList"); } // Pad and get its size padCommandBuffer(cb); auto usedSize = cb->curSize; // Release the buffer object to the pool freeBufferObj(sActiveBuffer[core]); sActiveBuffer[core] = nullptr; // Allocate a new buffer! if (core == getMainCoreId()) { sActiveBuffer[core] = allocateCommandBuffer(0x100); } return usedSize; }
Move<VkCommandBuffer> makeCommandBuffer (const DeviceInterface& vk, const VkDevice device, const VkCommandPool commandPool) { const VkCommandBufferAllocateInfo bufferAllocateParams = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; commandPool, // VkCommandPool commandPool; VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level; 1u, // deUint32 bufferCount; }; return allocateCommandBuffer(vk, device, &bufferAllocateParams); }
void initCommandBufferPool(virtual_ptr<uint32_t> base, uint32_t size, uint32_t itemSize) { auto core = coreinit::OSGetCoreId(); assert(gx2::internal::getMainCoreId() == core); gCommandBufferPool.base = base; gCommandBufferPool.size = size; gCommandBufferPool.itemSize = itemSize; gCommandBufferPool.items.resize(size / gCommandBufferPool.itemSize); gActiveBuffer[core] = allocateCommandBuffer(); }
pm4::Buffer * getCommandBuffer(uint32_t size) { auto core = coreinit::OSGetCoreId(); auto &active = gActiveBuffer[core]; if (!active) { active = allocateCommandBuffer(); } else if (active->curSize + size > active->maxSize) { active = flushCommandBuffer(active); } return active; }
void initCommandBufferPool(uint32_t *base, uint32_t size) { auto core = coreinit::OSGetCoreId(); decaf_check(gx2::internal::getMainCoreId() == core); sBufferPoolBase = base; sBufferPoolEnd = sBufferPoolBase + size; sBufferPoolHeadPtr = sBufferPoolBase; sBufferPoolTailPtr = nullptr; sActiveBuffer[core] = allocateCommandBuffer(0x100); }
pm4::Buffer * flushCommandBuffer(pm4::Buffer *cb) { auto core = coreinit::OSGetCoreId(); if (!cb) { cb = gActiveBuffer[core]; } else if (cb != gActiveBuffer[core]) { throw std::logic_error("Attempting to flush non-active buffer"); } if (!cb) { return nullptr; } if (cb->userBuffer) { void *newList = nullptr; uint32_t newSize = 0; // End the active display list GX2EndDisplayList(cb->buffer); // Ask user to allocate new display list std::tie(newList, newSize) = displayListOverrun(cb->buffer, cb->curSize * 4); if (!newList || !newSize) { throw std::logic_error("Unable to handle display list overrun"); } // Begin new display list, it will update gActiveBuffer GX2BeginDisplayList(newList, newSize); } else { // Send buffer to our driver! gpu::queueCommandBuffer(cb); // Allocate new buffer gActiveBuffer[core] = allocateCommandBuffer(); } return gActiveBuffer[core]; }
pm4::Buffer * flushCommandBuffer(uint32_t neededSize) { auto core = coreinit::OSGetCoreId(); auto cb = sActiveBuffer[core]; decaf_check(cb); if (cb->displayList) { void *newList = nullptr; uint32_t newSize = 0; // End the active display list padCommandBuffer(cb); // Ask user to allocate new display list std::tie(newList, newSize) = displayListOverrun(cb->buffer, cb->curSize * 4, neededSize * 4); if (!newList || !newSize) { decaf_abort("Unable to handle display list overrun"); } // Record the new information returned from the application cb->buffer = reinterpret_cast<uint32_t *>(newList); cb->curSize = 0; cb->maxSize = newSize / 4; return cb; } // Flush the existing buffer flushActiveCommandBuffer(); // Allocate new buffer sActiveBuffer[core] = allocateCommandBuffer(neededSize); return sActiveBuffer[core]; }
bool VKRenderPass::VBuildCommandList() { if (!allocateCommandBuffer()) return false; if (m_instanceBlock.buffer != VK_NULL_HANDLE) DeleteUniformBuffer(m_device, m_instanceBlock); //Create block of data for instance variables if (m_instanceDataSize > 0) { if (!CreateUniformBuffer(m_device, m_instanceDataSize, m_instanceData, &m_instanceBlock)) return false; } //Setup the order of the commands we will issue in the command list BuildRenderRequestHeirarchy(); VkResult err; VKRenderer* renderer = VKRenderer::RendererInstance; VkCommandBufferInheritanceInfo inheritanceInfo = {}; inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; inheritanceInfo.pNext = nullptr; inheritanceInfo.renderPass = VK_NULL_HANDLE; inheritanceInfo.subpass = 0; inheritanceInfo.framebuffer = VK_NULL_HANDLE; inheritanceInfo.occlusionQueryEnable = VK_FALSE; inheritanceInfo.queryFlags = 0; inheritanceInfo.pipelineStatistics = 0; VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.pNext = nullptr; beginInfo.flags = 0; beginInfo.pInheritanceInfo = &inheritanceInfo; //Get the current clear color from the renderer VkClearValue clearColor = renderer->GetClearColor(); std::vector<VkClearValue> clearValues; for (size_t i = 0; i < m_outputRenderTargets.size(); i++) { VKRenderTargetHandle vkTarget= m_outputRenderTargets[i].DynamicCastHandle<VKRenderTarget>(); const VkClearValue* targetClearColor = vkTarget->GetClearColor(); //If a clear color is provided by the render target, lets use that if (targetClearColor == nullptr) clearValues.push_back(clearColor); else clearValues.push_back(*targetClearColor); } clearValues.push_back({1.0f, 0.0f}); VkRenderPassBeginInfo renderPassBeginInfo = {}; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassBeginInfo.pNext = nullptr; renderPassBeginInfo.renderPass = m_renderPass; renderPassBeginInfo.framebuffer = m_framebuffer; renderPassBeginInfo.renderArea.offset.x = 0; renderPassBeginInfo.renderArea.offset.y = 0; renderPassBeginInfo.renderArea.extent.width = m_width; renderPassBeginInfo.renderArea.extent.height = m_height; renderPassBeginInfo.clearValueCount = static_cast<uint32_t>(clearValues.size()); renderPassBeginInfo.pClearValues = clearValues.data(); VkViewport viewport = {}; viewport.width = static_cast<float>(m_width); viewport.height = static_cast<float>(m_height); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor = {}; scissor.extent.width = m_width; scissor.extent.height = m_height; scissor.offset.x = 0; scissor.offset.y = 0; err = vkBeginCommandBuffer(m_commandBuffer, &beginInfo); assert(!err); if (err != VK_SUCCESS) { HT_DEBUG_PRINTF("VKRenderPass::VBuildCommandList(): Failed to build command buffer.\n"); return false; } /* BEGIN BUFFER COMMANDS */ vkCmdBeginRenderPass(m_commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdSetViewport(m_commandBuffer, 0, 1, &viewport); vkCmdSetScissor(m_commandBuffer, 0, 1, &scissor); std::map<IPipelineHandle, std::vector<RenderableInstances>>::iterator iterator; for (iterator = m_pipelineList.begin(); iterator != m_pipelineList.end(); iterator++) { VKPipelineHandle pipeline = iterator->first.DynamicCastHandle<VKPipeline>(); //Calculate inverse view proj Math::Matrix4 invViewProj = Math::MMMatrixTranspose(Math::MMMatrixInverse(m_view)); m_view = Math::MMMatrixTranspose(m_view); m_proj = Math::MMMatrixTranspose(m_proj); pipeline->VSetMatrix4("pass.0proj", m_proj); pipeline->VSetMatrix4("pass.1view", m_view); pipeline->VSetMatrix4("pass.2invViewProj", invViewProj); pipeline->VSetInt("pass.3width", m_width); pipeline->VSetInt("pass.4height", m_height); pipeline->VUpdate(); VkPipeline vkPipeline = pipeline->GetVKPipeline(); VkPipelineLayout vkPipelineLayout = renderer->GetVKRootLayoutHandle()->VKGetPipelineLayout(); vkCmdBindPipeline(m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline); pipeline->SendPushConstants(m_commandBuffer, vkPipelineLayout); //Bind input textures if(m_inputTargetDescriptorSets.size() > 0) vkCmdBindDescriptorSets(m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipelineLayout, m_firstInputTargetSetIndex, static_cast<uint32_t>(m_inputTargetDescriptorSets.size()), m_inputTargetDescriptorSets.data(), 0, nullptr); std::vector<RenderableInstances> renderables = iterator->second; VkDeviceSize offsets[] = { 0 }; for (uint32_t i = 0; i < renderables.size(); i++) { Renderable renderable = renderables[i].renderable; uint32_t count = renderables[i].count; VKMaterialHandle material = renderable.material.DynamicCastHandle<VKMaterial>(); VKMeshHandle mesh = renderable.mesh.DynamicCastHandle<VKMesh>(); std::vector<VkDescriptorSet> descriptorSets = material->GetVKDescriptorSets(); //Bind material descriptor sets vkCmdBindDescriptorSets(m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipelineLayout, 0, static_cast<uint32_t>(descriptorSets.size()), descriptorSets.data(), 0, nullptr); //Bind instance buffer if(m_instanceDataSize > 0) vkCmdBindVertexBuffers(m_commandBuffer, 1, 1, &m_instanceBlock.buffer, offsets); UniformBlock_vk vertBlock = mesh->GetVertexBlock(); UniformBlock_vk indexBlock = mesh->GetIndexBlock(); uint32_t indexCount = mesh->GetIndexCount(); vkCmdBindVertexBuffers(m_commandBuffer, 0, 1, &vertBlock.buffer, offsets); vkCmdBindIndexBuffer(m_commandBuffer, indexBlock.buffer, 0, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed(m_commandBuffer, indexCount, count, 0, 0, 0); } } vkCmdEndRenderPass(m_commandBuffer); /* END BUFFER COMMANDS */ //Blit to render targets for (size_t i = 0; i < m_outputRenderTargets.size(); i++) { VKRenderTargetHandle renderTarget = m_outputRenderTargets[i].DynamicCastHandle<VKRenderTarget>(); if (!renderTarget->Blit(m_commandBuffer, m_colorImages[i])) return false; } err = vkEndCommandBuffer(m_commandBuffer); assert(!err); if (err != VK_SUCCESS) { HT_DEBUG_PRINTF("VKRenderPass::VBuildCommandList(): Failed to end command buffer.\n"); return false; } //Delete instance data delete[] m_instanceData; m_instanceData = nullptr; m_instanceDataSize = 0; return true; }