void PhysXRigidbody::updateMassDistribution() { if (((UINT32)mFlags & (UINT32)Flag::AutoTensors) == 0) return; if (((UINT32)mFlags & (UINT32)Flag::AutoMass) == 0) { PxRigidBodyExt::setMassAndUpdateInertia(*mInternal, mInternal->getMass()); } else { UINT32 numShapes = mInternal->getNbShapes(); if (numShapes == 0) { PxRigidBodyExt::setMassAndUpdateInertia(*mInternal, mInternal->getMass()); return; } PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes); mInternal->getShapes(shapes, numShapes); float* masses = (float*)bs_stack_alloc(sizeof(float) * numShapes); for (UINT32 i = 0; i < numShapes; i++) masses[i] = ((Collider*)shapes[i]->userData)->getMass(); PxRigidBodyExt::setMassAndUpdateInertia(*mInternal, masses, numShapes); bs_stack_free(masses); bs_stack_free(shapes); } }
VkPipelineLayout VulkanDescriptorManager::getPipelineLayout(VulkanDescriptorLayout** layouts, UINT32 numLayouts) { VulkanPipelineLayoutKey key(layouts, numLayouts); auto iterFind = mPipelineLayouts.find(key); if (iterFind != mPipelineLayouts.end()) return iterFind->second; // Create new VkDescriptorSetLayout* setLayouts = (VkDescriptorSetLayout*)bs_stack_alloc(sizeof(VkDescriptorSetLayout) * numLayouts); for(UINT32 i = 0; i < numLayouts; i++) setLayouts[i] = layouts[i]->getHandle(); VkPipelineLayoutCreateInfo layoutCI; layoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; layoutCI.pNext = nullptr; layoutCI.flags = 0; layoutCI.pushConstantRangeCount = 0; layoutCI.pPushConstantRanges = nullptr; layoutCI.setLayoutCount = numLayouts; layoutCI.pSetLayouts = setLayouts; VkPipelineLayout pipelineLayout; VkResult result = vkCreatePipelineLayout(mDevice.getLogical(), &layoutCI, gVulkanAllocator, &pipelineLayout); assert(result == VK_SUCCESS); bs_stack_free(setLayouts); key.layouts = (VulkanDescriptorLayout**)bs_alloc(sizeof(VulkanDescriptorLayout*) * numLayouts); memcpy(key.layouts, layouts, sizeof(VulkanDescriptorLayout*) * numLayouts); mPipelineLayouts.insert(std::make_pair(key, pipelineLayout)); return pipelineLayout; }
void PhysXRigidbody::setFlags(Flag flags) { bool ccdEnabledOld = mInternal->getRigidBodyFlags() & PxRigidBodyFlag::eENABLE_CCD; bool ccdEnabledNew = ((UINT32)flags & (UINT32)Flag::CCD) != 0; if(ccdEnabledOld != ccdEnabledNew) { if(ccdEnabledNew) { if (!gPhysics().hasFlag(PhysicsFlag::CCD_Enable)) LOGWRN("Enabling CCD on a Rigidbody but CCD is not enabled globally."); } mInternal->setRigidBodyFlag(PxRigidBodyFlag::eENABLE_CCD, ccdEnabledNew); // Enable/disable CCD on shapes so the filter can handle them properly UINT32 numShapes = mInternal->getNbShapes(); PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes); mInternal->getShapes(shapes, sizeof(PxShape*) * numShapes); for (UINT32 i = 0; i < numShapes; i++) { Collider* collider = (Collider*)shapes[i]->userData; collider->_getInternal()->_setCCD(ccdEnabledNew); } } Rigidbody::setFlags(flags); }
void AudioUtility::convertBitDepth(const UINT8* input, UINT32 inBitDepth, UINT8* output, UINT32 outBitDepth, UINT32 numSamples) { INT32* srcBuffer = nullptr; bool needTempBuffer = inBitDepth != 32; if (needTempBuffer) srcBuffer = (INT32*)bs_stack_alloc(numSamples * sizeof(INT32)); else srcBuffer = (INT32*)input; // Note: I convert to a temporary 32-bit buffer and then use that to convert to actual requested bit depth. // It would be more efficient to convert directly from source to requested depth without a temporary buffer, // at the cost of additional complexity. If this method ever becomes a performance issue consider that. switch (inBitDepth) { case 8: convert8To32Bits(input, srcBuffer, numSamples); break; case 16: convert16To32Bits((INT16*)input, srcBuffer, numSamples); break; case 24: BansheeEngine::convert24To32Bits(input, srcBuffer, numSamples); break; case 32: // Do nothing break; default: assert(false); break; } switch (outBitDepth) { case 8: convert32To8Bits(srcBuffer, output, numSamples); break; case 16: convert32To16Bits(srcBuffer, (INT16*)output, numSamples); break; case 24: convert32To24Bits(srcBuffer, output, numSamples); break; case 32: memcpy(output, srcBuffer, numSamples * sizeof(INT32)); break; default: assert(false); break; } if (needTempBuffer) { bs_stack_free(srcBuffer); srcBuffer = nullptr; } }
void PhysXRigidbody::removeColliders() { UINT32 numShapes = mInternal->getNbShapes(); PxShape** shapes = (PxShape**)bs_stack_alloc(sizeof(PxShape*) * numShapes); mInternal->getShapes(shapes, sizeof(PxShape*) * numShapes); for (UINT32 i = 0; i < numShapes; i++) { Collider* collider = (Collider*)shapes[i]->userData; collider->_getInternal()->_setCCD(false); mInternal->detachShape(*shapes[i]); } bs_stack_free(shapes); }
void TriangleClipperBase::getOrderedVertices(const ClipFace& face, UINT32* sortedVerts) { UINT32 numEdges = (UINT32)face.edges.size(); UINT32* sortedEdges = (UINT32*)bs_stack_alloc(sizeof(UINT32) * numEdges); for (UINT32 i = 0; i < numEdges; i++) sortedEdges[i] = face.edges[i]; // Bubble sort to arrange edges in contiguous order for (UINT32 i0 = 0, i1 = 1, choice = 1; i1 < numEdges - 1; i0 = i1, i1++) { const ClipEdge& edge0 = mesh.edges[sortedEdges[i0]]; UINT32 current = edge0.verts[choice]; for (UINT32 j = i1; j < numEdges; j++) { const ClipEdge& edge1 = mesh.edges[sortedEdges[j]]; if (edge1.verts[0] == current || edge1.verts[1] == current) { std::swap(sortedEdges[i1], sortedEdges[j]); choice = 1; break; } } } // Add the first two vertices sortedVerts[0] = mesh.edges[sortedEdges[0]].verts[0]; sortedVerts[1] = mesh.edges[sortedEdges[0]].verts[1]; // Add the remaining vertices for (UINT32 i = 1; i < numEdges; i++) { const ClipEdge& edge = mesh.edges[sortedEdges[i]]; if (edge.verts[0] == sortedVerts[i]) sortedVerts[i + 1] = edge.verts[1]; else sortedVerts[i + 1] = edge.verts[0]; } bs_stack_free(sortedEdges); }
void TriangleClipperBase::getOrderedFaces(FrameVector<FrameVector<UINT32>>& sortedFaces) { for (UINT32 i = 0; i < (UINT32)mesh.faces.size(); i++) { const ClipFace& face = mesh.faces[i]; if (face.visible) { // Get the ordered vertices of the face. The first and last // element of the array are the same since the polyline is // closed. UINT32 numSortedVerts = (UINT32)face.edges.size() + 1; UINT32* sortedVerts = (UINT32*)bs_stack_alloc(sizeof(UINT32) * numSortedVerts); getOrderedVertices(face, sortedVerts); FrameVector<UINT32> faceVerts; // The convention is that the vertices should be counterclockwise // ordered when viewed from the negative side of the plane of the // face. If you need the opposite convention, switch the // inequality in the if-else statement. Vector3 normal = getNormal(sortedVerts, numSortedVerts); if (Vector3::dot(mesh.faces[i].normal, normal) < 0) { // Clockwise, need to swap for (INT32 j = (INT32)numSortedVerts - 2; j >= 0; j--) faceVerts.push_back(sortedVerts[j]); } else { // Counterclockwise for (int j = 0; j <= (INT32)numSortedVerts - 2; j++) faceVerts.push_back(sortedVerts[j]); } sortedFaces.push_back(faceVerts); bs_stack_free(sortedVerts); } } }
void VulkanGraphicsPipelineState::initialize() { Lock(mMutex); GraphicsPipelineState::initialize(); std::pair<VkShaderStageFlagBits, GpuProgram*> stages[] = { { VK_SHADER_STAGE_VERTEX_BIT, mData.vertexProgram.get() }, { VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, mData.hullProgram.get() }, { VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, mData.domainProgram.get() }, { VK_SHADER_STAGE_GEOMETRY_BIT, mData.geometryProgram.get() }, { VK_SHADER_STAGE_FRAGMENT_BIT, mData.fragmentProgram.get() } }; UINT32 stageOutputIdx = 0; UINT32 numStages = sizeof(stages) / sizeof(stages[0]); for(UINT32 i = 0; i < numStages; i++) { VulkanGpuProgram* program = static_cast<VulkanGpuProgram*>(stages[i].second); if (program == nullptr) continue; VkPipelineShaderStageCreateInfo& stageCI = mShaderStageInfos[stageOutputIdx]; stageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stageCI.pNext = nullptr; stageCI.flags = 0; stageCI.stage = stages[i].first; stageCI.module = VK_NULL_HANDLE; stageCI.pName = program->getProperties().getEntryPoint().c_str(); stageCI.pSpecializationInfo = nullptr; stageOutputIdx++; } UINT32 numUsedStages = stageOutputIdx; bool tesselationEnabled = mData.hullProgram != nullptr && mData.domainProgram != nullptr; mInputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; mInputAssemblyInfo.pNext = nullptr; mInputAssemblyInfo.flags = 0; mInputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // Assigned at runtime mInputAssemblyInfo.primitiveRestartEnable = false; mTesselationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; mTesselationInfo.pNext = nullptr; mTesselationInfo.flags = 0; mTesselationInfo.patchControlPoints = 3; // Assigned at runtime mViewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; mViewportInfo.pNext = nullptr; mViewportInfo.flags = 0; mViewportInfo.viewportCount = 1; // Spec says this need to be at least 1... mViewportInfo.scissorCount = 1; mViewportInfo.pViewports = nullptr; // Dynamic mViewportInfo.pScissors = nullptr; // Dynamic RasterizerState* rasterizerState = getRasterizerState().get(); if (rasterizerState == nullptr) rasterizerState = RasterizerState::getDefault().get(); BlendState* blendState = getBlendState().get(); if (blendState == nullptr) blendState = BlendState::getDefault().get(); DepthStencilState* depthStencilState = getDepthStencilState().get(); if (depthStencilState == nullptr) depthStencilState = DepthStencilState::getDefault().get(); const RasterizerProperties& rstProps = rasterizerState->getProperties(); const BlendProperties& blendProps = blendState->getProperties(); const DepthStencilProperties dsProps = depthStencilState->getProperties(); mRasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; mRasterizationInfo.pNext = nullptr; mRasterizationInfo.flags = 0; mRasterizationInfo.depthClampEnable = !rstProps.getDepthClipEnable(); mRasterizationInfo.rasterizerDiscardEnable = VK_FALSE; mRasterizationInfo.polygonMode = VulkanUtility::getPolygonMode(rstProps.getPolygonMode()); mRasterizationInfo.cullMode = VulkanUtility::getCullMode(rstProps.getCullMode()); mRasterizationInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; mRasterizationInfo.depthBiasEnable = rstProps.getDepthBias() != 0.0f; mRasterizationInfo.depthBiasConstantFactor = rstProps.getDepthBias(); mRasterizationInfo.depthBiasSlopeFactor = rstProps.getSlopeScaledDepthBias(); mRasterizationInfo.depthBiasClamp = mRasterizationInfo.depthClampEnable ? rstProps.getDepthBiasClamp() : 0.0f; mRasterizationInfo.lineWidth = 1.0f; mMultiSampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; mMultiSampleInfo.pNext = nullptr; mMultiSampleInfo.flags = 0; mMultiSampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; // Assigned at runtime mMultiSampleInfo.sampleShadingEnable = VK_FALSE; // When enabled, perform shading per sample instead of per pixel (more expensive, essentially FSAA) mMultiSampleInfo.minSampleShading = 1.0f; // Minimum percent of samples to run full shading for when sampleShadingEnable is enabled (1.0f to run for all) mMultiSampleInfo.pSampleMask = nullptr; // Normally one bit for each sample: e.g. 0x0000000F to enable all samples in a 4-sample setup mMultiSampleInfo.alphaToCoverageEnable = blendProps.getAlphaToCoverageEnabled(); mMultiSampleInfo.alphaToOneEnable = VK_FALSE; VkStencilOpState stencilFrontInfo; stencilFrontInfo.compareOp = VulkanUtility::getCompareOp(dsProps.getStencilFrontCompFunc()); stencilFrontInfo.depthFailOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontZFailOp()); stencilFrontInfo.passOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontPassOp()); stencilFrontInfo.failOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontFailOp()); stencilFrontInfo.reference = 0; // Dynamic stencilFrontInfo.compareMask = (UINT32)dsProps.getStencilReadMask(); stencilFrontInfo.writeMask = (UINT32)dsProps.getStencilWriteMask(); VkStencilOpState stencilBackInfo; stencilBackInfo.compareOp = VulkanUtility::getCompareOp(dsProps.getStencilBackCompFunc()); stencilBackInfo.depthFailOp = VulkanUtility::getStencilOp(dsProps.getStencilBackZFailOp()); stencilBackInfo.passOp = VulkanUtility::getStencilOp(dsProps.getStencilBackPassOp()); stencilBackInfo.failOp = VulkanUtility::getStencilOp(dsProps.getStencilBackFailOp()); stencilBackInfo.reference = 0; // Dynamic stencilBackInfo.compareMask = (UINT32)dsProps.getStencilReadMask(); stencilBackInfo.writeMask = (UINT32)dsProps.getStencilWriteMask(); mDepthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; mDepthStencilInfo.pNext = nullptr; mDepthStencilInfo.flags = 0; mDepthStencilInfo.depthBoundsTestEnable = false; mDepthStencilInfo.minDepthBounds = 0.0f; mDepthStencilInfo.maxDepthBounds = 1.0f; mDepthStencilInfo.depthTestEnable = dsProps.getDepthReadEnable(); mDepthStencilInfo.depthWriteEnable = dsProps.getDepthWriteEnable(); mDepthStencilInfo.depthCompareOp = VulkanUtility::getCompareOp(dsProps.getDepthComparisonFunc()); mDepthStencilInfo.front = stencilFrontInfo; mDepthStencilInfo.back = stencilBackInfo; mDepthStencilInfo.stencilTestEnable = dsProps.getStencilEnable(); for(UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++) { UINT32 rtIdx = 0; if (blendProps.getIndependantBlendEnable()) rtIdx = i; VkPipelineColorBlendAttachmentState& blendState = mAttachmentBlendStates[i]; blendState.blendEnable = blendProps.getBlendEnabled(rtIdx); blendState.colorBlendOp = VulkanUtility::getBlendOp(blendProps.getBlendOperation(rtIdx)); blendState.srcColorBlendFactor = VulkanUtility::getBlendFactor(blendProps.getSrcBlend(rtIdx)); blendState.dstColorBlendFactor = VulkanUtility::getBlendFactor(blendProps.getDstBlend(rtIdx)); blendState.alphaBlendOp = VulkanUtility::getBlendOp(blendProps.getAlphaBlendOperation(rtIdx)); blendState.srcAlphaBlendFactor = VulkanUtility::getBlendFactor(blendProps.getAlphaSrcBlend(rtIdx)); blendState.dstAlphaBlendFactor = VulkanUtility::getBlendFactor(blendProps.getAlphaDstBlend(rtIdx)); blendState.colorWriteMask = blendProps.getRenderTargetWriteMask(rtIdx) & 0xF; } mColorBlendStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; mColorBlendStateInfo.pNext = nullptr; mColorBlendStateInfo.flags = 0; mColorBlendStateInfo.logicOpEnable = VK_FALSE; mColorBlendStateInfo.logicOp = VK_LOGIC_OP_NO_OP; mColorBlendStateInfo.attachmentCount = 0; // Assigned at runtime mColorBlendStateInfo.pAttachments = mAttachmentBlendStates; mColorBlendStateInfo.blendConstants[0] = 0.0f; mColorBlendStateInfo.blendConstants[1] = 0.0f; mColorBlendStateInfo.blendConstants[2] = 0.0f; mColorBlendStateInfo.blendConstants[3] = 0.0f; mDynamicStates[0] = VK_DYNAMIC_STATE_VIEWPORT; mDynamicStates[1] = VK_DYNAMIC_STATE_SCISSOR; mDynamicStates[2] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; UINT32 numDynamicStates = sizeof(mDynamicStates) / sizeof(mDynamicStates[0]); assert(numDynamicStates == 3); mDynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; mDynamicStateInfo.pNext = nullptr; mDynamicStateInfo.flags = 0; mDynamicStateInfo.dynamicStateCount = numDynamicStates; mDynamicStateInfo.pDynamicStates = mDynamicStates; mPipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; mPipelineInfo.pNext = nullptr; mPipelineInfo.flags = 0; mPipelineInfo.stageCount = numUsedStages; mPipelineInfo.pStages = mShaderStageInfos; mPipelineInfo.pVertexInputState = nullptr; // Assigned at runtime mPipelineInfo.pInputAssemblyState = &mInputAssemblyInfo; mPipelineInfo.pTessellationState = tesselationEnabled ? &mTesselationInfo : nullptr; mPipelineInfo.pViewportState = &mViewportInfo; mPipelineInfo.pRasterizationState = &mRasterizationInfo; mPipelineInfo.pMultisampleState = &mMultiSampleInfo; mPipelineInfo.pDepthStencilState = nullptr; // Assigned at runtime mPipelineInfo.pColorBlendState = nullptr; // Assigned at runtime mPipelineInfo.pDynamicState = &mDynamicStateInfo; mPipelineInfo.renderPass = VK_NULL_HANDLE; // Assigned at runtime mPipelineInfo.layout = VK_NULL_HANDLE; // Assigned at runtime mPipelineInfo.subpass = 0; mPipelineInfo.basePipelineHandle = VK_NULL_HANDLE; mPipelineInfo.basePipelineIndex = -1; mScissorEnabled = rstProps.getScissorEnable(); if(mData.vertexProgram != nullptr) mVertexDecl = mData.vertexProgram->getInputDeclaration(); VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance()); VulkanDevice* devices[BS_MAX_DEVICES]; VulkanUtility::getDevices(rapi, mDeviceMask, devices); for (UINT32 i = 0; i < BS_MAX_DEVICES; i++) { if (devices[i] == nullptr) continue; mPerDeviceData[i].device = devices[i]; VulkanDescriptorManager& descManager = mPerDeviceData[i].device->getDescriptorManager(); VulkanGpuPipelineParamInfo& vkParamInfo = static_cast<VulkanGpuPipelineParamInfo&>(*mParamInfo); UINT32 numLayouts = vkParamInfo.getNumSets(); VulkanDescriptorLayout** layouts = (VulkanDescriptorLayout**)bs_stack_alloc(sizeof(VulkanDescriptorLayout*) * numLayouts); for (UINT32 j = 0; j < numLayouts; j++) layouts[j] = vkParamInfo.getLayout(i, j); mPerDeviceData[i].pipelineLayout = descManager.getPipelineLayout(layouts, numLayouts); bs_stack_free(layouts); } BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineState); }
void VulkanComputePipelineState::initialize() { ComputePipelineState::initialize(); // This might happen fairly often if shaders with unsupported languages are loaded, in which case the pipeline // will never get used, and its fine not to initialize it. if (!mProgram->isCompiled()) return; VulkanGpuProgram* vkProgram = static_cast<VulkanGpuProgram*>(mProgram.get()); VkPipelineShaderStageCreateInfo stageCI; stageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stageCI.pNext = nullptr; stageCI.flags = 0; stageCI.stage = VK_SHADER_STAGE_COMPUTE_BIT; stageCI.module = VK_NULL_HANDLE; stageCI.pName = vkProgram->getProperties().getEntryPoint().c_str(); stageCI.pSpecializationInfo = nullptr; VkComputePipelineCreateInfo pipelineCI; pipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; pipelineCI.pNext = nullptr; pipelineCI.flags = 0; pipelineCI.stage = stageCI; pipelineCI.basePipelineHandle = VK_NULL_HANDLE; pipelineCI.basePipelineIndex = -1; VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance()); VulkanDevice* devices[BS_MAX_DEVICES]; VulkanUtility::getDevices(rapi, mDeviceMask, devices); for (UINT32 i = 0; i < BS_MAX_DEVICES; i++) { if (devices[i] == nullptr) continue; mPerDeviceData[i].device = devices[i]; VulkanDescriptorManager& descManager = devices[i]->getDescriptorManager(); VulkanResourceManager& rescManager = devices[i]->getResourceManager(); VulkanGpuPipelineParamInfo& vkParamInfo = static_cast<VulkanGpuPipelineParamInfo&>(*mParamInfo); UINT32 numLayouts = vkParamInfo.getNumSets(); VulkanDescriptorLayout** layouts = (VulkanDescriptorLayout**)bs_stack_alloc(sizeof(VulkanDescriptorLayout*) * numLayouts); for (UINT32 j = 0; j < numLayouts; j++) layouts[j] = vkParamInfo.getLayout(i, j); VulkanShaderModule* module = vkProgram->getShaderModule(i); if (module != nullptr) pipelineCI.stage.module = module->getHandle(); else pipelineCI.stage.module = VK_NULL_HANDLE; pipelineCI.layout = descManager.getPipelineLayout(layouts, numLayouts); VkPipeline pipeline; VkResult result = vkCreateComputePipelines(devices[i]->getLogical(), VK_NULL_HANDLE, 1, &pipelineCI, gVulkanAllocator, &pipeline); assert(result == VK_SUCCESS); mPerDeviceData[i].pipeline = rescManager.create<VulkanPipeline>(pipeline); mPerDeviceData[i].pipelineLayout = pipelineCI.layout; bs_stack_free(layouts); } BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineState); }
void IconUtility::updateIconExe(const Path& path, const Map<UINT32, SPtr<PixelData>>& pixelsPerSize) { // A PE file is structured as such: // - MSDOS Header // - PE Signature // - COFF Header // - PE Optional Header // - One or multiple sections // - .code // - .data // - ... // - .rsrc // - icon/cursor/etc data std::fstream stream; stream.open(path.toPlatformString().c_str(), std::ios::in | std::ios::out | std::ios::binary); // First check magic number to ensure file is even an executable UINT16 magicNum; stream.read((char*)&magicNum, sizeof(magicNum)); if (magicNum != MSDOS_SIGNATURE) BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable."); // Read the MSDOS header and skip over it stream.seekg(0); MSDOSHeader msdosHeader; stream.read((char*)&msdosHeader, sizeof(MSDOSHeader)); // Read PE signature stream.seekg(msdosHeader.lfanew); UINT32 peSignature; stream.read((char*)&peSignature, sizeof(peSignature)); if (peSignature != PE_SIGNATURE) BS_EXCEPT(InvalidStateException, "Provided file is not in PE format."); // Read COFF header COFFHeader coffHeader; stream.read((char*)&coffHeader, sizeof(COFFHeader)); if (coffHeader.sizeOptHeader == 0) // .exe files always have an optional header BS_EXCEPT(InvalidStateException, "Provided file is not a valid executable."); UINT32 numSectionHeaders = coffHeader.numSections; // Read optional header auto optionalHeaderPos = stream.tellg(); UINT16 optionalHeaderSignature; stream.read((char*)&optionalHeaderSignature, sizeof(optionalHeaderSignature)); PEDataDirectory* dataDirectory = nullptr; stream.seekg(optionalHeaderPos); if (optionalHeaderSignature == PE_32BIT_SIGNATURE) { PEOptionalHeader32 optionalHeader; stream.read((char*)&optionalHeader, sizeof(optionalHeader)); dataDirectory = optionalHeader.dataDirectory + PE_IMAGE_DIRECTORY_ENTRY_RESOURCE; } else if (optionalHeaderSignature == PE_64BIT_SIGNATURE) { PEOptionalHeader64 optionalHeader; stream.read((char*)&optionalHeader, sizeof(optionalHeader)); dataDirectory = optionalHeader.dataDirectory + PE_IMAGE_DIRECTORY_ENTRY_RESOURCE; } else BS_EXCEPT(InvalidStateException, "Unrecognized PE format."); // Read section headers auto sectionHeaderPos = optionalHeaderPos + (std::ifstream::pos_type)coffHeader.sizeOptHeader; stream.seekg(sectionHeaderPos); PESectionHeader* sectionHeaders = bs_stack_alloc<PESectionHeader>(numSectionHeaders); stream.read((char*)sectionHeaders, sizeof(PESectionHeader) * numSectionHeaders); // Look for .rsrc section header std::function<void(PEImageResourceDirectory*, PEImageResourceDirectory*, UINT8*, UINT32)> setIconData = [&](PEImageResourceDirectory* base, PEImageResourceDirectory* current, UINT8* imageData, UINT32 sectionAddress) { UINT32 numEntries = current->numIdEntries; // Not supporting name entries PEImageResourceEntry* entries = (PEImageResourceEntry*)(current + 1); for (UINT32 i = 0; i < numEntries; i++) { // Only at root does the type identify resource type if (base == current && entries[i].type != PE_IMAGE_RT_ICON) continue; if (entries[i].isDirectory) { PEImageResourceDirectory* child = (PEImageResourceDirectory*)(((UINT8*)base) + entries[i].offsetDirectory); setIconData(base, child, imageData, sectionAddress); } else { PEImageResourceEntryData* data = (PEImageResourceEntryData*)(((UINT8*)base) + entries[i].offsetDirectory); UINT8* iconData = imageData + (data->offsetData - sectionAddress); updateIconData(iconData, pixelsPerSize); } } }; for (UINT32 i = 0; i < numSectionHeaders; i++) { if (sectionHeaders[i].flags & PE_SECTION_UNINITIALIZED_DATA) continue; if (strcmp(sectionHeaders[i].name, ".rsrc") == 0) { UINT32 imageSize = sectionHeaders[i].physicalSize; UINT8* imageData = (UINT8*)bs_stack_alloc(imageSize); stream.seekg(sectionHeaders[i].physicalAddress); stream.read((char*)imageData, imageSize); UINT32 resourceDirOffset = dataDirectory->virtualAddress - sectionHeaders[i].relativeVirtualAddress; PEImageResourceDirectory* resourceDirectory = (PEImageResourceDirectory*)&imageData[resourceDirOffset]; setIconData(resourceDirectory, resourceDirectory, imageData, sectionHeaders[i].relativeVirtualAddress); stream.seekp(sectionHeaders[i].physicalAddress); stream.write((char*)imageData, imageSize); bs_stack_free(imageData); } } bs_stack_free(sectionHeaders); stream.close(); }
void OAAudioClip::initialize() { { Lock lock(mMutex); // Needs to be called even if stream data is null, to ensure memory fence is added so the // other thread sees properly initialized AudioClip members AudioDataInfo info; info.bitDepth = mDesc.bitDepth; info.numChannels = mDesc.numChannels; info.numSamples = mNumSamples; info.sampleRate = mDesc.frequency; // If we need to keep source data, read everything into memory and keep a copy if (mKeepSourceData) { mStreamData->seek(mStreamOffset); UINT8* sampleBuffer = (UINT8*)bs_alloc(mStreamSize); mStreamData->read(sampleBuffer, mStreamSize); mSourceStreamData = bs_shared_ptr_new<MemoryDataStream>(sampleBuffer, mStreamSize); mSourceStreamSize = mStreamSize; } // Load decompressed data into a sound buffer bool loadDecompressed = mDesc.readMode == AudioReadMode::LoadDecompressed || (mDesc.readMode == AudioReadMode::LoadCompressed && mDesc.format == AudioFormat::PCM); if(loadDecompressed) { // Read all data into memory SPtr<DataStream> stream; UINT32 offset = 0; if (mSourceStreamData != nullptr) // If it's already loaded in memory, use it directly stream = mSourceStreamData; else { stream = mStreamData; offset = mStreamOffset; } UINT32 bufferSize = info.numSamples * (info.bitDepth / 8); UINT8* sampleBuffer = (UINT8*)bs_stack_alloc(bufferSize); // Decompress from Ogg if (mDesc.format == AudioFormat::VORBIS) { OggVorbisDecoder reader; if (reader.open(stream, info, offset)) reader.read(sampleBuffer, info.numSamples); else LOGERR("Failed decompressing AudioClip stream."); } // Load directly else { stream->seek(offset); stream->read(sampleBuffer, bufferSize); } alGenBuffers(1, &mBufferId); gOAAudio()._writeToOpenALBuffer(mBufferId, sampleBuffer, info); mStreamData = nullptr; mStreamOffset = 0; mStreamSize = 0; bs_stack_free(sampleBuffer); } // Load compressed data for streaming from memory else if(mDesc.readMode == AudioReadMode::LoadCompressed) { // If reading from file, make a copy of data in memory, otherwise just take ownership of the existing buffer if (mStreamData->isFile()) { if (mSourceStreamData != nullptr) // If it's already loaded in memory, use it directly mStreamData = mSourceStreamData; else { UINT8* data = (UINT8*)bs_alloc(mStreamSize); mStreamData->seek(mStreamOffset); mStreamData->read(data, mStreamSize); mStreamData = bs_shared_ptr_new<MemoryDataStream>(data, mStreamSize); } mStreamOffset = 0; } } // Keep original stream for streaming from file else { // Do nothing } if (mDesc.format == AudioFormat::VORBIS && mDesc.readMode != AudioReadMode::LoadDecompressed) { mNeedsDecompression = true; if (mStreamData != nullptr) { if (!mVorbisReader.open(mStreamData, info, mStreamOffset)) LOGERR("Failed decompressing AudioClip stream."); } } } AudioClip::initialize(); }
void MonoAssembly::load(MonoDomain* domain) { if (mIsLoaded) unload(); // Load assembly from memory because mono_domain_assembly_open keeps a lock on the file SPtr<DataStream> assemblyStream = FileSystem::openFile(mPath, true); if (assemblyStream == nullptr) { LOGERR("Cannot load assembly at path \"" + toString(mPath) + "\" because the file doesn't exist"); return; } UINT32 assemblySize = (UINT32)assemblyStream->size(); char* assemblyData = (char*)bs_stack_alloc(assemblySize); assemblyStream->read(assemblyData, assemblySize); String imageName = Path(mPath).getFilename(); MonoImageOpenStatus status = MONO_IMAGE_OK; MonoImage* image = mono_image_open_from_data_with_name(assemblyData, assemblySize, true, &status, false, imageName.c_str()); bs_stack_free(assemblyData); if (status != MONO_IMAGE_OK || image == nullptr) { LOGERR("Failed loading image data for assembly \"" + toString(mPath) + "\""); return; } // Load MDB file #if BS_DEBUG_MODE Path mdbPath = mPath + L".mdb"; if (FileSystem::exists(mdbPath)) { SPtr<DataStream> mdbStream = FileSystem::openFile(mdbPath, true); if (mdbStream != nullptr) { UINT32 mdbSize = (UINT32)mdbStream->size(); mDebugData = (UINT8*)bs_alloc(mdbSize); mdbStream->read(mDebugData, mdbSize); mono_debug_open_image_from_memory(image, mDebugData, mdbSize); } } #endif mMonoAssembly = mono_assembly_load_from_full(image, imageName.c_str(), &status, false); if (status != MONO_IMAGE_OK || mMonoAssembly == nullptr) { LOGERR("Failed loading assembly \"" + toString(mPath) + "\""); return; } mMonoImage = image; if(mMonoImage == nullptr) { BS_EXCEPT(InvalidParametersException, "Cannot get script assembly image."); } mIsLoaded = true; mIsDependency = false; }
void FMODAudioClip::initialize() { AudioFileInfo info; info.bitDepth = mDesc.bitDepth; info.numChannels = mDesc.numChannels; info.numSamples = mNumSamples; info.sampleRate = mDesc.frequency; // If we need to keep source data, read everything into memory and keep a copy if (mKeepSourceData) { mStreamData->seek(mStreamOffset); UINT8* sampleBuffer = (UINT8*)bs_alloc(mStreamSize); mStreamData->read(sampleBuffer, mStreamSize); mSourceStreamData = bs_shared_ptr_new<MemoryDataStream>(sampleBuffer, mStreamSize); mSourceStreamSize = mStreamSize; } FMOD::System* fmod = gFMODAudio()._getFMOD(); FMOD_MODE flags = FMOD_OPENMEMORY; if (is3D()) flags |= FMOD_3D; else flags |= FMOD_2D; // Load data into a sound buffer // TODO - Vorbis cannot be decompressed from memory by FMOD. Instead we force AudioReadMode::Stream for it. if(mDesc.readMode == AudioReadMode::LoadDecompressed || (mDesc.readMode == AudioReadMode::LoadCompressed && mDesc.format != AudioFormat::VORBIS)) { // Read all data into memory SPtr<DataStream> stream; UINT32 offset = 0; if (mSourceStreamData != nullptr) // If it's already loaded in memory, use it directly stream = mSourceStreamData; else { stream = mStreamData; offset = mStreamOffset; } UINT32 bufferSize = info.numSamples * (info.bitDepth / 8); UINT8* sampleBuffer = (UINT8*)bs_stack_alloc(bufferSize); stream->seek(offset); stream->read(sampleBuffer, bufferSize); FMOD_CREATESOUNDEXINFO exInfo; memset(&exInfo, 0, sizeof(exInfo)); exInfo.cbsize = sizeof(exInfo); exInfo.length = bufferSize; bool loadCompressed = mDesc.readMode == AudioReadMode::LoadCompressed && mDesc.format != AudioFormat::PCM; if (loadCompressed) flags |= FMOD_CREATECOMPRESSEDSAMPLE; else flags |= FMOD_CREATESAMPLE; if(fmod->createSound((const char*)sampleBuffer, flags, &exInfo, &mSound) != FMOD_OK) { LOGERR("Failed playing sound."); } else { mSound->setMode(FMOD_LOOP_OFF); } mStreamData = nullptr; mStreamOffset = 0; mStreamSize = 0; bs_stack_free(sampleBuffer); } else // Streaming { // Do nothing, we rely on AudioSource from creating sounds as only one streaming sound can ever be playing } AudioClip::initialize(); }
void GLSLGpuProgram::initialize() { #if BS_OPENGL_4_5 static const char* VERSION_CHARS = "450"; #elif BS_OPENGL_4_4 static const char* VERSION_CHARS = "440"; #elif BS_OPENGL_4_3 static const char* VERSION_CHARS = "430"; #elif BS_OPENGL_4_2 static const char* VERSION_CHARS = "420"; #else static const char* VERSION_CHARS = "410"; #endif if (!isSupported()) { mIsCompiled = false; mCompileMessages = "Specified GPU program type is not supported by the current render system."; GpuProgram::initialize(); return; } GLenum shaderType = 0x0000; switch (mType) { case GPT_VERTEX_PROGRAM: shaderType = GL_VERTEX_SHADER; mProgramID = ++sVertexShaderCount; break; case GPT_FRAGMENT_PROGRAM: shaderType = GL_FRAGMENT_SHADER; mProgramID = ++sFragmentShaderCount; break; #if BS_OPENGL_4_1 || BS_OPENGLES_3_2 case GPT_GEOMETRY_PROGRAM: shaderType = GL_GEOMETRY_SHADER; mProgramID = ++sGeometryShaderCount; break; case GPT_HULL_PROGRAM: shaderType = GL_TESS_CONTROL_SHADER; mProgramID = ++sDomainShaderCount; break; case GPT_DOMAIN_PROGRAM: shaderType = GL_TESS_EVALUATION_SHADER; mProgramID = ++sHullShaderCount; break; #endif #if BS_OPENGL_4_3 || BS_OPENGLES_3_1 case GPT_COMPUTE_PROGRAM: shaderType = GL_COMPUTE_SHADER; mProgramID = ++sComputeShaderCount; break; #endif default: break; } // Add preprocessor extras and main source const String& source = mSource; if (!source.empty()) { Vector<GLchar*> lines; const char* versionStr = "#version "; UINT32 versionStrLen = (UINT32)strlen(versionStr); UINT32 lineLength = 0; INT32 versionLineNum = -1; for (UINT32 i = 0; i < source.size(); i++) { if (source[i] == '\n' || source[i] == '\r') { assert(sizeof(source[i]) == sizeof(GLchar)); GLchar* lineData = (GLchar*)bs_stack_alloc(sizeof(GLchar) * (lineLength + 2)); memcpy(lineData, &source[i - lineLength], sizeof(GLchar) * lineLength); lineData[lineLength] = '\n'; lineData[lineLength + 1] = '\0'; if(versionLineNum == -1 && lineLength >= versionStrLen) { bool isEqual = true; for (UINT32 j = 0; j < versionStrLen; ++j) { if(lineData[j] != versionStr[j]) { isEqual = false; break; } } if (isEqual) versionLineNum = (INT32)lines.size(); } lines.push_back(lineData); lineLength = 0; } else { lineLength++; } } if (lineLength > 0) { UINT32 end = (UINT32)source.size() - 1; assert(sizeof(source[end]) == sizeof(GLchar)); GLchar* lineData = (GLchar*)bs_stack_alloc(sizeof(GLchar) * (lineLength + 1)); memcpy(lineData, &source[source.size() - lineLength], sizeof(GLchar) * lineLength); lineData[lineLength] = '\0'; lines.push_back(lineData); lineLength = 0; } int numInsertedLines = 0; if(versionLineNum == -1) { char versionLine[50]; strcpy(versionLine, "#version "); strcat(versionLine, VERSION_CHARS); strcat(versionLine, "\n"); UINT32 length = (UINT32)strlen(versionLine) + 1; GLchar* extraLineData = (GLchar*)bs_stack_alloc(length); memcpy(extraLineData, versionLine, length); lines.insert(lines.begin(), extraLineData); numInsertedLines++; } char versionDefine[50]; strcpy(versionDefine, "#define OPENGL"); strcat(versionDefine, VERSION_CHARS); strcat(versionDefine, "\n"); const char* EXTRA_LINES[] = { "#define OPENGL\n", versionDefine }; UINT32 numExtraLines = sizeof(EXTRA_LINES) / sizeof(EXTRA_LINES[0]); UINT32 extraLineOffset = versionLineNum != -1 ? versionLineNum + 1 : 0; for (UINT32 i = 0; i < numExtraLines; i++) { UINT32 length = (UINT32)strlen(EXTRA_LINES[i]) + 1; GLchar* extraLineData = (GLchar*)bs_stack_alloc(length); memcpy(extraLineData, EXTRA_LINES[i], length); lines.insert(lines.begin() + extraLineOffset + numInsertedLines, extraLineData); numInsertedLines++; } StringStream codeStream; for(auto& entry : lines) codeStream << entry; for (INT32 i = numInsertedLines - 1; i >= 0; i--) bs_stack_free(lines[extraLineOffset + i]); if (numInsertedLines > 0) lines.erase(lines.begin() + extraLineOffset, lines.begin() + extraLineOffset + numInsertedLines); for (auto iter = lines.rbegin(); iter != lines.rend(); ++iter) bs_stack_free(*iter); String code = codeStream.str(); const char* codeRaw = code.c_str(); mGLHandle = glCreateShaderProgramv(shaderType, 1, (const GLchar**)&codeRaw); BS_CHECK_GL_ERROR(); mCompileMessages = ""; mIsCompiled = !checkForGLSLError(mGLHandle, mCompileMessages); } if (mIsCompiled) { GLSLParamParser paramParser; paramParser.buildUniformDescriptions(mGLHandle, mType, *mParametersDesc); if (mType == GPT_VERTEX_PROGRAM) { Vector<VertexElement> elementList = paramParser.buildVertexDeclaration(mGLHandle); mInputDeclaration = HardwareBufferManager::instance().createVertexDeclaration(elementList); } } BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram); GpuProgram::initialize(); }