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); } }
void GUIPanel::_updateLayoutInternal(const GUILayoutData& data) { GUILayoutData childData = data; _updateDepthRange(childData); UINT32 numElements = (UINT32)mChildren.size(); Rect2I* elementAreas = nullptr; if (numElements > 0) elementAreas = bs_stack_new<Rect2I>(numElements); _getElementAreas(data.area, elementAreas, numElements, mChildSizeRanges, mSizeRange); UINT32 childIdx = 0; for (auto& child : mChildren) { if (child->_isActive()) { childData.area = elementAreas[childIdx]; _updateChildLayout(child, childData); } childIdx++; } if (elementAreas != nullptr) bs_stack_free(elementAreas); }
void GUILayoutX::_updateLayoutInternal(const GUILayoutData& data) { UINT32 numElements = (UINT32)mChildren.size(); Rect2I* elementAreas = nullptr; if (numElements > 0) elementAreas = bs_stack_new<Rect2I>(numElements); _getElementAreas(data.area, elementAreas, numElements, mChildSizeRanges, mSizeRange); // Now that we have all the areas, actually assign them UINT32 childIdx = 0; GUILayoutData childData = data; for(auto& child : mChildren) { if (child->_isActive()) { childData.area = elementAreas[childIdx]; childData.clipRect = childData.area; childData.clipRect.clip(data.clipRect); child->_setLayoutData(childData); child->_updateLayoutInternal(childData); } childIdx++; } if(elementAreas != nullptr) bs_stack_free(elementAreas); }
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 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 VulkanTexture::copyImage(VulkanTransferBuffer* cb, VulkanImage* srcImage, VulkanImage* dstImage, VkImageLayout srcFinalLayout, VkImageLayout dstFinalLayout) { UINT32 numFaces = mProperties.getNumFaces(); UINT32 numMipmaps = mProperties.getNumMipmaps() + 1; UINT32 mipWidth = mProperties.getWidth(); UINT32 mipHeight = mProperties.getHeight(); UINT32 mipDepth = mProperties.getDepth(); VkImageCopy* imageRegions = bs_stack_alloc<VkImageCopy>(numMipmaps); for(UINT32 i = 0; i < numMipmaps; i++) { VkImageCopy& imageRegion = imageRegions[i]; imageRegion.srcOffset = { 0, 0, 0 }; imageRegion.dstOffset = { 0, 0, 0 }; imageRegion.extent = { mipWidth, mipHeight, mipDepth }; imageRegion.srcSubresource.baseArrayLayer = 0; imageRegion.srcSubresource.layerCount = numFaces; imageRegion.srcSubresource.mipLevel = i; imageRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageRegion.dstSubresource.baseArrayLayer = 0; imageRegion.dstSubresource.layerCount = numFaces; imageRegion.dstSubresource.mipLevel = i; imageRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; if (mipWidth != 1) mipWidth /= 2; if (mipHeight != 1) mipHeight /= 2; if (mipDepth != 1) mipDepth /= 2; } VkImageSubresourceRange range; range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; range.baseArrayLayer = 0; range.layerCount = numFaces; range.baseMipLevel = 0; range.levelCount = numMipmaps; VkImageLayout transferSrcLayout, transferDstLayout; if (mDirectlyMappable) { transferSrcLayout = VK_IMAGE_LAYOUT_GENERAL; transferDstLayout = VK_IMAGE_LAYOUT_GENERAL; } else { transferSrcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; transferDstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; } // Transfer textures to a valid layout cb->setLayout(srcImage, range, VK_ACCESS_TRANSFER_READ_BIT, transferSrcLayout); cb->setLayout(dstImage, range, VK_ACCESS_TRANSFER_WRITE_BIT, transferDstLayout); vkCmdCopyImage(cb->getCB()->getHandle(), srcImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, numMipmaps, imageRegions); // Transfer back to final layouts VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcFinalLayout); cb->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, srcAccessMask, transferSrcLayout, srcFinalLayout, range); VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstFinalLayout); cb->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask, transferDstLayout, dstFinalLayout, range); cb->getCB()->registerResource(srcImage, range, VulkanUseFlag::Read, ResourceUsage::Transfer); cb->getCB()->registerResource(dstImage, range, VulkanUseFlag::Write, ResourceUsage::Transfer); bs_stack_free(imageRegions); }
Vector2I GUILayoutUtility::calcActualSizeInternal(UINT32 width, UINT32 height, GUILayout* layout) { UINT32 numElements = (UINT32)layout->_getNumChildren(); Rect2I* elementAreas = nullptr; if (numElements > 0) elementAreas = bs_stack_new<Rect2I>(numElements); Rect2I parentArea; parentArea.width = width; parentArea.height = height; layout->_getElementAreas(parentArea, elementAreas, numElements, layout->_getCachedChildSizeRanges(), layout->_getCachedSizeRange()); Rect2I* actualAreas = elementAreas; // We re-use the same array for (UINT32 i = 0; i < numElements; i++) { GUIElementBase* child = layout->_getChild(i); Rect2I childArea = elementAreas[i]; if (child->_getType() == GUIElementBase::Type::Layout || child->_getType() == GUIElementBase::Type::Panel) { Vector2I childActualSize = calcActualSizeInternal(childArea.width, childArea.height, static_cast<GUILayout*>(child)); actualAreas[i].width = (UINT32)childActualSize.x; actualAreas[i].height = (UINT32)childActualSize.y; } else if (child->_getType() == GUIElementBase::Type::Element) { RectOffset padding = child->_getPadding(); actualAreas[i].width = elementAreas[i].width + padding.left + padding.right; actualAreas[i].height = elementAreas[i].height + padding.top + padding.bottom; } else { actualAreas[i].width = elementAreas[i].width; actualAreas[i].height = elementAreas[i].height; } } Vector2I min; Vector2I max; if (numElements > 0) { Rect2I childArea = actualAreas[0]; min = Vector2I(childArea.x, childArea.y); max = Vector2I(childArea.x + childArea.width, childArea.y + childArea.height); } for (UINT32 i = 1; i < numElements; i++) { Rect2I childArea = actualAreas[i]; min.x = std::min(min.x, childArea.x); min.y = std::min(min.y, childArea.y); max.x = std::max(max.x, childArea.x + (INT32)childArea.width); max.y = std::max(max.y, childArea.y + (INT32)childArea.height); } Vector2I actualSize = max - min; if (elementAreas != nullptr) bs_stack_free(elementAreas); return actualSize; }
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 VulkanSwapChain::rebuild(const SPtr<VulkanDevice>& device, VkSurfaceKHR surface, UINT32 width, UINT32 height, bool vsync, VkFormat colorFormat, VkColorSpaceKHR colorSpace, bool createDepth, VkFormat depthFormat) { mDevice = device; VkResult result; VkPhysicalDevice physicalDevice = device->getPhysical(); // Determine swap chain dimensions VkSurfaceCapabilitiesKHR surfaceCaps; result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCaps); assert(result == VK_SUCCESS); VkExtent2D swapchainExtent; // If width/height is 0xFFFFFFFF, we can manually specify width, height if (surfaceCaps.currentExtent.width == (uint32_t)-1 || surfaceCaps.currentExtent.height == (uint32_t)-1) { swapchainExtent.width = width; swapchainExtent.height = height; } else // Otherwise we must use the size we're given swapchainExtent = surfaceCaps.currentExtent; mWidth = swapchainExtent.width; mHeight = swapchainExtent.height; // Find present mode uint32_t numPresentModes; result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numPresentModes, nullptr); assert(result == VK_SUCCESS); assert(numPresentModes > 0); VkPresentModeKHR* presentModes = bs_stack_alloc<VkPresentModeKHR>(numPresentModes); result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numPresentModes, presentModes); assert(result == VK_SUCCESS); VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; if(!vsync) { for (UINT32 i = 0; i < numPresentModes; i++) { if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; break; } if (presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; } } else { // Mailbox comes with lower input latency than FIFO, but can waste GPU power by rendering frames that are never // displayed, especially if the app runs much faster than the refresh rate. This is a concern for mobiles. #if BS_PLATFORM != BS_PLATFORM_ANDROID && BS_PLATFORM != BS_PLATFORM_IOS for (UINT32 i = 0; i < numPresentModes; i++) { if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } } #endif } bs_stack_free(presentModes); uint32_t numImages = surfaceCaps.minImageCount; VkSurfaceTransformFlagsKHR transform; if (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; else transform = surfaceCaps.currentTransform; VkSwapchainCreateInfoKHR swapChainCI; swapChainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapChainCI.pNext = nullptr; swapChainCI.flags = 0; swapChainCI.surface = surface; swapChainCI.minImageCount = numImages; swapChainCI.imageFormat = colorFormat; swapChainCI.imageColorSpace = colorSpace; swapChainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height }; swapChainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapChainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)transform; swapChainCI.imageArrayLayers = 1; swapChainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapChainCI.queueFamilyIndexCount = 0; swapChainCI.pQueueFamilyIndices = NULL; swapChainCI.presentMode = presentMode; swapChainCI.oldSwapchain = mSwapChain; swapChainCI.clipped = VK_TRUE; swapChainCI.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; VkSwapchainKHR oldSwapChain = mSwapChain; VkDevice logicalDevice = device->getLogical(); result = vkCreateSwapchainKHR(logicalDevice, &swapChainCI, gVulkanAllocator, &mSwapChain); assert(result == VK_SUCCESS); clear(oldSwapChain); result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, nullptr); assert(result == VK_SUCCESS); // Get the swap chain images VkImage* images = bs_stack_alloc<VkImage>(numImages); result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, images); assert(result == VK_SUCCESS); VulkanResourceManager& resManager = device->getResourceManager(); VULKAN_IMAGE_DESC imageDesc; imageDesc.format = colorFormat; imageDesc.type = TEX_TYPE_2D; imageDesc.usage = TU_RENDERTARGET; imageDesc.layout = VK_IMAGE_LAYOUT_UNDEFINED; imageDesc.numFaces = 1; imageDesc.numMipLevels = 1; imageDesc.memory = VK_NULL_HANDLE; mSurfaces.resize(numImages); for (UINT32 i = 0; i < numImages; i++) { imageDesc.image = images[i]; mSurfaces[i].acquired = false; mSurfaces[i].needsWait = false; mSurfaces[i].image = resManager.create<VulkanImage>(imageDesc, false); mSurfaces[i].sync = resManager.create<VulkanSemaphore>(); } bs_stack_free(images); // Create depth stencil image if (createDepth) { VkImageCreateInfo depthStencilImageCI; depthStencilImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; depthStencilImageCI.pNext = nullptr; depthStencilImageCI.flags = 0; depthStencilImageCI.imageType = VK_IMAGE_TYPE_2D; depthStencilImageCI.format = depthFormat; depthStencilImageCI.extent = { width, height, 1 }; depthStencilImageCI.mipLevels = 1; depthStencilImageCI.arrayLayers = 1; depthStencilImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; depthStencilImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; depthStencilImageCI.samples = VK_SAMPLE_COUNT_1_BIT; depthStencilImageCI.tiling = VK_IMAGE_TILING_OPTIMAL; depthStencilImageCI.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; depthStencilImageCI.pQueueFamilyIndices = nullptr; depthStencilImageCI.queueFamilyIndexCount = 0; VkImage depthStencilImage; result = vkCreateImage(logicalDevice, &depthStencilImageCI, gVulkanAllocator, &depthStencilImage); assert(result == VK_SUCCESS); imageDesc.image = depthStencilImage; imageDesc.usage = TU_DEPTHSTENCIL; imageDesc.format = depthFormat; imageDesc.memory = mDevice->allocateMemory(depthStencilImage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); mDepthStencilImage = resManager.create<VulkanImage>(imageDesc, true); } else mDepthStencilImage = nullptr; // Create a framebuffer for each swap chain buffer UINT32 numFramebuffers = (UINT32)mSurfaces.size(); for (UINT32 i = 0; i < numFramebuffers; i++) { VULKAN_FRAMEBUFFER_DESC& desc = mSurfaces[i].framebufferDesc; desc.width = getWidth(); desc.height = getHeight(); desc.layers = 1; desc.numSamples = 1; desc.offscreen = false; desc.color[0].format = colorFormat; desc.color[0].image = mSurfaces[i].image; desc.color[0].surface = TextureSurface::COMPLETE; desc.color[0].baseLayer = 0; desc.depth.format = depthFormat; desc.depth.image = mDepthStencilImage; desc.depth.surface = TextureSurface::COMPLETE; desc.depth.baseLayer = 0; mSurfaces[i].framebuffer = resManager.create<VulkanFramebuffer>(desc); } }
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(); }
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 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 GUIScrollArea::_updateLayoutInternal(const GUILayoutData& data) { UINT32 numElements = (UINT32)mChildren.size(); Rect2I* elementAreas = nullptr; if (numElements > 0) elementAreas = bs_stack_new<Rect2I>(numElements); UINT32 layoutIdx = 0; UINT32 horzScrollIdx = 0; UINT32 vertScrollIdx = 0; for (UINT32 i = 0; i < numElements; i++) { GUIElementBase* child = _getChild(i); if (child == mContentLayout) layoutIdx = i; if (child == mHorzScroll) horzScrollIdx = i; if (child == mVertScroll) vertScrollIdx = i; } _getElementAreas(data.area, elementAreas, numElements, mChildSizeRanges, mVisibleSize, mContentSize); Rect2I& layoutBounds = elementAreas[layoutIdx]; Rect2I& horzScrollBounds = elementAreas[horzScrollIdx]; Rect2I& vertScrollBounds = elementAreas[vertScrollIdx]; // Recalculate offsets in case scroll percent got updated externally (this needs to be delayed to this point because // at the time of the update content and visible sizes might be out of date). UINT32 scrollableHeight = (UINT32)std::max(0, INT32(mContentSize.y) - INT32(mVisibleSize.y)); if (mRecalculateVertOffset) { mVertOffset = scrollableHeight * Math::clamp01(mVertScroll->getScrollPos()); mRecalculateVertOffset = false; } UINT32 scrollableWidth = (UINT32)std::max(0, INT32(mContentSize.x) - INT32(mVisibleSize.x)); if (mRecalculateHorzOffset) { mHorzOffset = scrollableWidth * Math::clamp01(mHorzScroll->getScrollPos()); mRecalculateHorzOffset = false; } // Reset offset in case layout size changed so everything fits mVertOffset = Math::clamp(mVertOffset, 0.0f, (float)scrollableHeight); mHorzOffset = Math::clamp(mHorzOffset, 0.0f, (float)scrollableWidth); // Layout if (mContentLayout->_isActive()) { layoutBounds.x -= Math::floorToInt(mHorzOffset); layoutBounds.y -= Math::floorToInt(mVertOffset); Rect2I layoutClipRect = data.clipRect; layoutClipRect.width = (UINT32)mVisibleSize.x; layoutClipRect.height = (UINT32)mVisibleSize.y; layoutClipRect.clip(data.clipRect); GUILayoutData layoutData = data; layoutData.area = layoutBounds; layoutData.clipRect = layoutClipRect; mContentLayout->_setLayoutData(layoutData); mContentLayout->_updateLayoutInternal(layoutData); } // Vertical scrollbar { GUILayoutData vertScrollData = data; vertScrollData.area = vertScrollBounds; vertScrollData.clipRect = vertScrollBounds; vertScrollData.clipRect.clip(data.clipRect); mVertScroll->_setLayoutData(vertScrollData); mVertScroll->_updateLayoutInternal(vertScrollData); // Set new handle size and update position to match the new size UINT32 scrollableHeight = (UINT32)std::max(0, INT32(mContentSize.y) - INT32(vertScrollBounds.height)); float newScrollPct = 0.0f; if (scrollableHeight > 0) newScrollPct = mVertOffset / scrollableHeight; mVertScroll->_setHandleSize(vertScrollBounds.height / (float)mContentSize.y); mVertScroll->_setScrollPos(newScrollPct); } // Horizontal scrollbar { GUILayoutData horzScrollData = data; horzScrollData.area = horzScrollBounds; horzScrollData.clipRect = horzScrollBounds; horzScrollData.clipRect.clip(data.clipRect); mHorzScroll->_setLayoutData(horzScrollData); mHorzScroll->_updateLayoutInternal(horzScrollData); // Set new handle size and update position to match the new size UINT32 scrollableWidth = (UINT32)std::max(0, INT32(mContentSize.x) - INT32(horzScrollBounds.width)); float newScrollPct = 0.0f; if (scrollableWidth > 0) newScrollPct = mHorzOffset / scrollableWidth; mHorzScroll->_setHandleSize(horzScrollBounds.width / (float)mContentSize.x); mHorzScroll->_setScrollPos(newScrollPct); } if (elementAreas != nullptr) bs_stack_free(elementAreas); }
void GUILayoutX::_getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements, const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const { assert(mChildren.size() == numElements); UINT32 totalOptimalSize = mySizeRange.optimal.x; UINT32 totalNonClampedSize = 0; UINT32 numNonClampedElements = 0; UINT32 numFlexibleSpaces = 0; bool* processedElements = nullptr; float* elementScaleWeights = nullptr; if (mChildren.size() > 0) { processedElements = bs_stack_alloc<bool>((UINT32)mChildren.size()); memset(processedElements, 0, mChildren.size() * sizeof(bool)); elementScaleWeights = bs_stack_alloc<float>((UINT32)mChildren.size()); memset(elementScaleWeights, 0, mChildren.size() * sizeof(float)); } // Set initial sizes, count number of children per type and mark fixed elements as already processed UINT32 childIdx = 0; for (auto& child : mChildren) { elementAreas[childIdx].width = sizeRanges[childIdx].optimal.x; if (child->_getType() == GUIElementBase::Type::FixedSpace) { processedElements[childIdx] = true; } else if (child->_getType() == GUIElementBase::Type::FlexibleSpace) { if (child->_isActive()) { numFlexibleSpaces++; numNonClampedElements++; } else processedElements[childIdx] = true; } else { const GUIDimensions& dimensions = child->_getDimensions(); if (dimensions.fixedWidth()) processedElements[childIdx] = true; else { if (elementAreas[childIdx].width > 0) { numNonClampedElements++; totalNonClampedSize += elementAreas[childIdx].width; } else processedElements[childIdx] = true; } } childIdx++; } // If there is some room left, calculate flexible space sizes (since they will fill up all that extra room) if ((UINT32)layoutArea.width > totalOptimalSize) { UINT32 extraSize = layoutArea.width - totalOptimalSize; UINT32 remainingSize = extraSize; // Flexible spaces always expand to fill up all unused space if (numFlexibleSpaces > 0) { float avgSize = remainingSize / (float)numFlexibleSpaces; childIdx = 0; for (auto& child : mChildren) { if (processedElements[childIdx]) { childIdx++; continue; } UINT32 extraWidth = std::min((UINT32)Math::ceilToInt(avgSize), remainingSize); UINT32 elementWidth = elementAreas[childIdx].width + extraWidth; // Clamp if needed if (child->_getType() == GUIElementBase::Type::FlexibleSpace) { processedElements[childIdx] = true; numNonClampedElements--; elementAreas[childIdx].width = elementWidth; remainingSize = (UINT32)std::max(0, (INT32)remainingSize - (INT32)extraWidth); } childIdx++; } totalOptimalSize = layoutArea.width; } } // Determine weight scale for every element. When scaling elements up/down they will be scaled based on this weight. // Weight is to ensure all elements are scaled fairly, so elements that are large will get effected more than smaller elements. childIdx = 0; float invOptimalSize = 1.0f / totalNonClampedSize; UINT32 childCount = (UINT32)mChildren.size(); for (UINT32 i = 0; i < childCount; i++) { if (processedElements[childIdx]) { childIdx++; continue; } elementScaleWeights[childIdx] = invOptimalSize * elementAreas[childIdx].width; childIdx++; } // Our optimal size is larger than maximum allowed, so we need to reduce size of some elements if (totalOptimalSize > (UINT32)layoutArea.width) { UINT32 extraSize = totalOptimalSize - layoutArea.width; UINT32 remainingSize = extraSize; // Iterate until we reduce everything so it fits, while maintaining // equal average sizes using the weights we calculated earlier while (remainingSize > 0 && numNonClampedElements > 0) { UINT32 totalRemainingSize = remainingSize; childIdx = 0; for (auto& child : mChildren) { if (processedElements[childIdx]) { childIdx++; continue; } float avgSize = totalRemainingSize * elementScaleWeights[childIdx]; UINT32 extraWidth = std::min((UINT32)Math::ceilToInt(avgSize), remainingSize); UINT32 elementWidth = (UINT32)std::max(0, (INT32)elementAreas[childIdx].width - (INT32)extraWidth); // Clamp if needed switch (child->_getType()) { case GUIElementBase::Type::FlexibleSpace: elementAreas[childIdx].width = 0; processedElements[childIdx] = true; numNonClampedElements--; break; case GUIElementBase::Type::Element: case GUIElementBase::Type::Layout: case GUIElementBase::Type::Panel: { const LayoutSizeRange& childSizeRange = sizeRanges[childIdx]; if (elementWidth == 0) { processedElements[childIdx] = true; numNonClampedElements--; } else if (childSizeRange.min.x > 0 && (INT32)elementWidth < childSizeRange.min.x) { elementWidth = childSizeRange.min.x; processedElements[childIdx] = true; numNonClampedElements--; } extraWidth = elementAreas[childIdx].width - elementWidth; elementAreas[childIdx].width = elementWidth; remainingSize = (UINT32)std::max(0, (INT32)remainingSize - (INT32)extraWidth); } break; case GUIElementBase::Type::FixedSpace: break; } childIdx++; } } } else // We are smaller than the allowed maximum, so try to expand some elements { UINT32 extraSize = layoutArea.width - totalOptimalSize; UINT32 remainingSize = extraSize; // Iterate until we reduce everything so it fits, while maintaining // equal average sizes using the weights we calculated earlier while (remainingSize > 0 && numNonClampedElements > 0) { UINT32 totalRemainingSize = remainingSize; childIdx = 0; for (auto& child : mChildren) { if (processedElements[childIdx]) { childIdx++; continue; } float avgSize = totalRemainingSize * elementScaleWeights[childIdx]; UINT32 extraWidth = std::min((UINT32)Math::ceilToInt(avgSize), remainingSize); UINT32 elementWidth = elementAreas[childIdx].width + extraWidth; // Clamp if needed switch (child->_getType()) { case GUIElementBase::Type::FlexibleSpace: processedElements[childIdx] = true; numNonClampedElements--; break; case GUIElementBase::Type::Element: case GUIElementBase::Type::Layout: case GUIElementBase::Type::Panel: { const LayoutSizeRange& childSizeRange = sizeRanges[childIdx]; if (elementWidth == 0) { processedElements[childIdx] = true; numNonClampedElements--; } else if (childSizeRange.max.x > 0 && (INT32)elementWidth > childSizeRange.max.x) { elementWidth = childSizeRange.max.x; processedElements[childIdx] = true; numNonClampedElements--; } extraWidth = elementWidth - elementAreas[childIdx].width; elementAreas[childIdx].width = elementWidth; remainingSize = (UINT32)std::max(0, (INT32)remainingSize - (INT32)extraWidth); } break; case GUIElementBase::Type::FixedSpace: break; } childIdx++; } } } // Compute offsets and height UINT32 xOffset = 0; childIdx = 0; for (auto& child : mChildren) { UINT32 elemWidth = elementAreas[childIdx].width; xOffset += child->_getPadding().left; const LayoutSizeRange& sizeRange = sizeRanges[childIdx]; UINT32 elemHeight = (UINT32)sizeRange.optimal.y; const GUIDimensions& dimensions = child->_getDimensions(); if (!dimensions.fixedHeight()) { elemHeight = layoutArea.height; if (sizeRange.min.y > 0 && elemHeight < (UINT32)sizeRange.min.y) elemHeight = (UINT32)sizeRange.min.y; if (sizeRange.max.y > 0 && elemHeight > (UINT32)sizeRange.max.y) elemHeight = (UINT32)sizeRange.max.y; } elementAreas[childIdx].height = elemHeight; if (child->_getType() == GUIElementBase::Type::Element) { GUIElement* element = static_cast<GUIElement*>(child); UINT32 yPadding = element->_getPadding().top + element->_getPadding().bottom; INT32 yOffset = Math::ceilToInt(((INT32)layoutArea.height - (INT32)(elemHeight + yPadding)) * 0.5f); yOffset = std::max(0, yOffset); elementAreas[childIdx].x = layoutArea.x + xOffset; elementAreas[childIdx].y = layoutArea.y + yOffset; } else { elementAreas[childIdx].x = layoutArea.x + xOffset; elementAreas[childIdx].y = layoutArea.y; } xOffset += elemWidth + child->_getPadding().right; childIdx++; } if (elementScaleWeights != nullptr) bs_stack_free(elementScaleWeights); if (processedElements != nullptr) bs_stack_free(processedElements); }