Skip to content

Commit 1ba6f3b

Browse files
author
Alexander Gauggel
committed
Clean up RenderBackend code
1 parent 7d2d101 commit 1ba6f3b

File tree

6 files changed

+114
-109
lines changed

6 files changed

+114
-109
lines changed

Plain/src/Runtime/Rendering/Backend/RenderBackend.cpp

Lines changed: 36 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "VulkanShader.h"
2424
#include "VulkanCommandRecording.h"
2525
#include "VulkanSampler.h"
26+
#include "VulkanBarrier.h"
2627

2728
// disable ImGui warnings
2829
#pragma warning( push )
@@ -422,7 +423,7 @@ void RenderBackend::renderFrame(const bool presentToScreen) {
422423
auto& swapchainPresentImage = m_images[m_swapchainInputImageHandle.index];
423424
const auto& transitionToPresentBarrier = createImageBarriers(swapchainPresentImage,
424425
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0, 1);
425-
barriersCommand(currentCommandBuffer, transitionToPresentBarrier, std::vector<VkBufferMemoryBarrier> {});
426+
issueBarriersCommand(currentCommandBuffer, transitionToPresentBarrier, std::vector<VkBufferMemoryBarrier> {});
426427

427428
auto res = vkEndCommandBuffer(currentCommandBuffer);
428429
assert(res == VK_SUCCESS);
@@ -702,8 +703,8 @@ struct ImageHandleDecoded {
702703

703704
ImageHandleDecoded decodeImageHandle(const ImageHandle handle) {
704705
ImageHandleDecoded decoded;
705-
decoded.isTempImage = bool(handle.index >> 31); //first bit indicates if image is temp
706-
decoded.index = handle.index & 0x7FFFFFFF; //mask out first bit for index
706+
decoded.isTempImage = bool(handle.index >> 31); // first bit indicates if image is temp
707+
decoded.index = handle.index & 0x7FFFFFFF; // mask out first bit for index
707708
return decoded;
708709
}
709710

@@ -733,11 +734,11 @@ std::vector<RenderPassBarriers> RenderBackend::createRenderPassBarriers() {
733734
const RenderPassResources& resources = execution.resources;
734735
RenderPassBarriers barriers;
735736

736-
//storage images
737+
// storage images
737738
for (const ImageResource& storageImage : resources.storageImages) {
738739
Image& image = getImageRef(storageImage.image);
739740

740-
//check if any mip levels need a layout transition
741+
// check if any mip levels need a layout transition
741742
const VkImageLayout requiredLayout = VK_IMAGE_LAYOUT_GENERAL;
742743
bool needsLayoutTransition = false;
743744
for (const auto& layout : image.layoutPerMip) {
@@ -746,8 +747,8 @@ std::vector<RenderPassBarriers> RenderBackend::createRenderPassBarriers() {
746747
}
747748
}
748749

749-
//check if image already has a barrier
750-
//can happen if same image is used as two storage image when accessing different mips
750+
// check if image already has a barrier
751+
// can happen if same image is used as two storage image when accessing different mips
751752
bool hasBarrierAlready = false;
752753
for (const auto& barrier : barriers.imageBarriers) {
753754
if (barrier.image == image.vulkanHandle) {
@@ -764,10 +765,10 @@ std::vector<RenderPassBarriers> RenderBackend::createRenderPassBarriers() {
764765
image.currentlyWriting = true;
765766
}
766767

767-
//sampled images
768+
// sampled images
768769
for (const ImageResource& sampledImage : resources.sampledImages) {
769770

770-
//use general layout if image is used as a storage image too
771+
// use general layout if image is used as a storage image too
771772
bool isUsedAsStorageImage = false;
772773
{
773774
for (const ImageResource& storageImage : resources.storageImages) {
@@ -783,7 +784,7 @@ std::vector<RenderPassBarriers> RenderBackend::createRenderPassBarriers() {
783784

784785
Image& image = getImageRef(sampledImage.image);
785786

786-
//check if any mip levels need a layout transition
787+
// check if any mip levels need a layout transition
787788
VkImageLayout requiredLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
788789

789790
bool needsLayoutTransition = false;
@@ -800,14 +801,14 @@ std::vector<RenderPassBarriers> RenderBackend::createRenderPassBarriers() {
800801
}
801802
}
802803

803-
//attachments
804+
// attachments
804805
if (executionEntry.type == RenderPassType::Graphic) {
805806
const GraphicPassExecution graphicExecutionInfo = m_graphicPassExecutions[executionEntry.index];
806807

807808
for (const RenderTarget& target : graphicExecutionInfo.targets) {
808809
Image& image = getImageRef(target.image);
809810

810-
//check if any mip levels need a layout transition
811+
// check if any mip levels need a layout transition
811812
const VkImageLayout requiredLayout = isVulkanDepthFormat(image.format) ?
812813
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
813814

@@ -830,18 +831,18 @@ std::vector<RenderPassBarriers> RenderBackend::createRenderPassBarriers() {
830831
}
831832
}
832833

833-
//storage buffer barriers
834+
// storage buffer barriers
834835
for (const auto& bufferResource : resources.storageBuffers) {
835-
StorageBufferHandle handle = bufferResource.buffer;
836-
Buffer& buffer = m_storageBuffers[handle.index];
837-
const bool needsBarrier = buffer.isBeingWritten;
838-
if (needsBarrier) {
839-
VkBufferMemoryBarrier barrier = createBufferBarrier(buffer, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
840-
barriers.memoryBarriers.push_back(barrier);
841-
}
836+
StorageBufferHandle handle = bufferResource.buffer;
837+
Buffer& buffer = m_storageBuffers[handle.index];
838+
const bool needsBarrier = buffer.isBeingWritten;
839+
if (needsBarrier) {
840+
VkBufferMemoryBarrier barrier = createBufferBarrier(buffer, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
841+
barriers.memoryBarriers.push_back(barrier);
842+
}
842843

843-
//update writing state
844-
buffer.isBeingWritten = !bufferResource.readOnly;
844+
// update writing state
845+
buffer.isBeingWritten = !bufferResource.readOnly;
845846
}
846847
barrierList.push_back(barriers);
847848
}
@@ -881,7 +882,7 @@ void RenderBackend::submitGraphicPass(const GraphicPassExecution& execution,
881882
timeQuery.name = pass.graphicPassDesc.name;
882883
timeQuery.startQuery = issueTimestampQuery(commandBuffer, m_frameIndexMod2);
883884

884-
barriersCommand(commandBuffer, barriers.imageBarriers, barriers.memoryBarriers);
885+
issueBarriersCommand(commandBuffer, barriers.imageBarriers, barriers.memoryBarriers);
885886

886887
const glm::ivec2 resolution = getResolutionFromRenderTargets(execution.targets);
887888
const auto beginInfo = createBeginInfo(resolution.x, resolution.y, pass.vulkanRenderPass,
@@ -921,7 +922,7 @@ void RenderBackend::submitComputePass(const ComputePassExecution& execution,
921922
timeQuery.name = pass.computePassDesc.name;
922923
timeQuery.startQuery = issueTimestampQuery(commandBuffer, m_frameIndexMod2);
923924

924-
barriersCommand(commandBuffer, barriers.imageBarriers, barriers.memoryBarriers);
925+
issueBarriersCommand(commandBuffer, barriers.imageBarriers, barriers.memoryBarriers);
925926

926927
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pass.pipeline);
927928

@@ -1477,7 +1478,7 @@ void RenderBackend::manualImageLayoutTransition(Image& image, const VkImageLayou
14771478
const auto transitionCmdBuffer = beginOneTimeUseCommandBuffer();
14781479
const auto newLayoutBarriers = createImageBarriers(image, newLayout,
14791480
VK_ACCESS_TRANSFER_WRITE_BIT, 0, (uint32_t)image.viewPerMip.size());
1480-
barriersCommand(transitionCmdBuffer, newLayoutBarriers, std::vector<VkBufferMemoryBarrier> {});
1481+
issueBarriersCommand(transitionCmdBuffer, newLayoutBarriers, std::vector<VkBufferMemoryBarrier> {});
14811482

14821483
auto res = vkEndCommandBuffer(transitionCmdBuffer);
14831484
checkVulkanResult(res);
@@ -1566,7 +1567,7 @@ Buffer RenderBackend::createBufferInternal(const VkDeviceSize size, const std::v
15661567

15671568
VkImageSubresourceLayers RenderBackend::createSubresourceLayers(const Image& image, const uint32_t mipLevel) {
15681569
VkImageSubresourceLayers layers;
1569-
layers.aspectMask = isVulkanDepthFormat(image.format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
1570+
layers.aspectMask = getVkImageAspectFlags(image.format);
15701571
layers.mipLevel = mipLevel;
15711572
layers.baseArrayLayer = 0;
15721573
layers.layerCount = 1;
@@ -1660,7 +1661,7 @@ void RenderBackend::transferDataIntoImage(Image& target, const void* data, const
16601661
const auto toTransferDstBarrier = createImageBarriers(target, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
16611662
VK_ACCESS_TRANSFER_READ_BIT, 0, (uint32_t)target.viewPerMip.size());
16621663

1663-
barriersCommand(copyBuffer, toTransferDstBarrier, std::vector<VkBufferMemoryBarrier> {});
1664+
issueBarriersCommand(copyBuffer, toTransferDstBarrier, std::vector<VkBufferMemoryBarrier> {});
16641665
}
16651666

16661667

@@ -1745,7 +1746,7 @@ void RenderBackend::generateMipChain(Image& image, const VkImageLayout newLayout
17451746
const auto dstBarriers = createImageBarriers(image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, srcMip + 1, 1); //dst
17461747
barriers.insert(barriers.end(), dstBarriers.begin(), dstBarriers.end());
17471748

1748-
barriersCommand(blitCmdBuffer, barriers, std::vector<VkBufferMemoryBarrier> {});
1749+
issueBarriersCommand(blitCmdBuffer, barriers, std::vector<VkBufferMemoryBarrier> {});
17491750

17501751
//blit operation
17511752
blitInfo.srcSubresource = createSubresourceLayers(image, srcMip );
@@ -1766,7 +1767,7 @@ void RenderBackend::generateMipChain(Image& image, const VkImageLayout newLayout
17661767

17671768
//bring image into new layout
17681769
const auto newLayoutBarriers = createImageBarriers(image, newLayout, VK_ACCESS_TRANSFER_WRITE_BIT, 0, (uint32_t)image.viewPerMip.size());
1769-
barriersCommand(blitCmdBuffer, newLayoutBarriers, std::vector<VkBufferMemoryBarrier> {});
1770+
issueBarriersCommand(blitCmdBuffer, newLayoutBarriers, std::vector<VkBufferMemoryBarrier> {});
17701771

17711772
//end recording
17721773
auto res = vkEndCommandBuffer(blitCmdBuffer);
@@ -2398,76 +2399,27 @@ bool validateAttachmentFormatsAreCompatible(const ImageFormat a, const ImageForm
23982399
return imageFormatToVkAspectFlagBits(a) == imageFormatToVkAspectFlagBits(b);
23992400
}
24002401

2401-
void RenderBackend::barriersCommand(const VkCommandBuffer commandBuffer,
2402-
const std::vector<VkImageMemoryBarrier>& imageBarriers, const std::vector<VkBufferMemoryBarrier>& memoryBarriers) {
2403-
2404-
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr,
2405-
(uint32_t)memoryBarriers.size(), memoryBarriers.data(), (uint32_t)imageBarriers.size(), imageBarriers.data());
2406-
}
2407-
24082402
std::vector<VkImageMemoryBarrier> RenderBackend::createImageBarriers(Image& image, const VkImageLayout newLayout,
24092403
const VkAccessFlags dstAccess, const uint32_t baseMip, const uint32_t mipLevels) {
24102404

2411-
VkImageAspectFlags aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
2412-
const bool isDepthImage = isVulkanDepthFormat(image.format);
2413-
if (isDepthImage) {
2414-
aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT;
2415-
}
2416-
24172405
std::vector<VkImageMemoryBarrier> barriers;
2418-
2419-
const uint32_t layerCount = computeImageLayerCount(image.desc.type);
2420-
2421-
// first barrier
2422-
VkImageMemoryBarrier firstBarrier;
2423-
firstBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2424-
firstBarrier.pNext = nullptr;
2425-
firstBarrier.srcAccessMask = image.currentAccess;
2426-
firstBarrier.dstAccessMask = dstAccess;
2427-
firstBarrier.oldLayout = image.layoutPerMip[baseMip];
2428-
firstBarrier.newLayout = newLayout;
2429-
firstBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2430-
firstBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2431-
firstBarrier.image = image.vulkanHandle;
2432-
firstBarrier.subresourceRange.aspectMask = aspectFlags;
2433-
firstBarrier.subresourceRange.baseMipLevel = baseMip;
2434-
firstBarrier.subresourceRange.levelCount = 1;
2435-
firstBarrier.subresourceRange.baseArrayLayer = 0;
2436-
firstBarrier.subresourceRange.layerCount = layerCount;
2406+
const VkImageMemoryBarrier firstBarrier = createImageBarrier(image, dstAccess, newLayout, baseMip);
24372407
barriers.push_back(firstBarrier);
24382408

24392409
// add subsequent mip level barriers
2440-
for (uint32_t i = 1; i < mipLevels; i++) {
2410+
for (uint32_t mipOffset = 1; mipOffset < mipLevels; mipOffset++) {
24412411

2442-
// same mip layout: extens subresource range
2443-
uint32_t mipLevel = baseMip + i;
2444-
if (image.layoutPerMip[mipLevel] == barriers.back().oldLayout) {
2412+
uint32_t mipLevel = baseMip + mipOffset;
2413+
const bool canExtendLastBarrier = image.layoutPerMip[mipLevel] == barriers.back().oldLayout;
2414+
if (canExtendLastBarrier) {
24452415
barriers.back().subresourceRange.levelCount++;
24462416
}
2447-
2448-
// different mip layout: new barrier
24492417
else {
2450-
VkImageMemoryBarrier barrier;
2451-
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2452-
barrier.pNext = nullptr;
2453-
barrier.srcAccessMask = image.currentAccess;
2454-
barrier.dstAccessMask = dstAccess;
2455-
barrier.oldLayout = image.layoutPerMip[mipLevel];
2456-
barrier.newLayout = newLayout;
2457-
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2458-
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2459-
barrier.image = image.vulkanHandle;
2460-
barrier.subresourceRange.aspectMask = aspectFlags;
2461-
barrier.subresourceRange.baseMipLevel = mipLevel;
2462-
barrier.subresourceRange.levelCount = 1;
2463-
barrier.subresourceRange.baseArrayLayer = 0;
2464-
barrier.subresourceRange.layerCount = layerCount;
2465-
2418+
const VkImageMemoryBarrier barrier = createImageBarrier(image, dstAccess, newLayout, mipLevel);
24662419
barriers.push_back(barrier);
24672420
}
24682421
}
24692422

2470-
// update image properties
24712423
for (uint32_t i = baseMip; i < baseMip + mipLevels; i++) {
24722424
image.layoutPerMip[i] = newLayout;
24732425
}
@@ -2477,20 +2429,6 @@ std::vector<VkImageMemoryBarrier> RenderBackend::createImageBarriers(Image& imag
24772429
return barriers;
24782430
}
24792431

2480-
VkBufferMemoryBarrier RenderBackend::createBufferBarrier(const Buffer& buffer, const VkAccessFlagBits srcAccess, const VkAccessFlagBits dstAccess) {
2481-
VkBufferMemoryBarrier barrier;
2482-
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
2483-
barrier.pNext = nullptr;
2484-
barrier.srcAccessMask = srcAccess;
2485-
barrier.srcAccessMask = dstAccess;
2486-
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2487-
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2488-
barrier.buffer = buffer.vulkanHandle;
2489-
barrier.offset = 0;
2490-
barrier.size = buffer.size;
2491-
return barrier;
2492-
}
2493-
24942432
VkQueryPool RenderBackend::createQueryPool(const VkQueryType queryType, const uint32_t queryCount) {
24952433

24962434
VkQueryPoolCreateInfo createInfo;

Plain/src/Runtime/Rendering/Backend/RenderBackend.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -363,22 +363,17 @@ class RenderBackend {
363363
=========
364364
*/
365365

366-
//actual creation of internal objects
367-
//split from public function to allow use when reloading shader
366+
// actual creation of internal objects
367+
// split from public function to allow use when reloading shader
368368
ComputePass createComputePassInternal(const ComputePassDescription& desc, const std::vector<uint32_t>& spirV);
369369
GraphicPass createGraphicPassInternal(const GraphicPassDescription& desc, const GraphicPassShaderSpirV& spirV);
370370

371-
//renderpass barriers
372-
void barriersCommand(const VkCommandBuffer commandBuffer, const std::vector<VkImageMemoryBarrier>& imageBarriers, const std::vector<VkBufferMemoryBarrier>& memoryBarriers);
373-
374-
//create necessary image barriers
375-
//multiple barriers may be needed, as mip levels may have differing layouts
376-
//sets image.layout to newLayout, image.currentAccess to dstAccess and image.currentlyWriting to false
371+
// create necessary image barriers
372+
// multiple barriers may be needed, as mip levels may have differing layouts
373+
// sets image.layout to newLayout, image.currentAccess to dstAccess and image.currentlyWriting to false
377374
std::vector<VkImageMemoryBarrier> createImageBarriers(Image& image, const VkImageLayout newLayout,
378375
const VkAccessFlags dstAccess, const uint32_t baseMip, const uint32_t mipLevels);
379376

380-
VkBufferMemoryBarrier createBufferBarrier(const Buffer& buffer, const VkAccessFlagBits srcAccess, const VkAccessFlagBits dstAccess);
381-
382377
/*
383378
=========
384379
sync objects
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "pch.h"
2+
#include "VulkanBarrier.h"
3+
#include "VulkanImage.h"
4+
5+
VkBufferMemoryBarrier createBufferBarrier(const Buffer& buffer,
6+
const VkAccessFlagBits srcAccess, const VkAccessFlagBits dstAccess) {
7+
8+
VkBufferMemoryBarrier barrier;
9+
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
10+
barrier.pNext = nullptr;
11+
barrier.srcAccessMask = srcAccess;
12+
barrier.srcAccessMask = dstAccess;
13+
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
14+
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
15+
barrier.buffer = buffer.vulkanHandle;
16+
barrier.offset = 0;
17+
barrier.size = buffer.size;
18+
return barrier;
19+
}
20+
21+
VkImageMemoryBarrier createImageBarrier(const Image& image, const VkAccessFlags dstAccess,
22+
const VkImageLayout newLayout, const size_t mipLevel) {
23+
24+
VkImageMemoryBarrier barrier;
25+
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
26+
barrier.pNext = nullptr;
27+
barrier.srcAccessMask = image.currentAccess;
28+
barrier.dstAccessMask = dstAccess;
29+
barrier.oldLayout = image.layoutPerMip[mipLevel];
30+
barrier.newLayout = newLayout;
31+
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
32+
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
33+
barrier.image = image.vulkanHandle;
34+
barrier.subresourceRange.aspectMask = getVkImageAspectFlags(image.format);
35+
barrier.subresourceRange.baseMipLevel = mipLevel;
36+
barrier.subresourceRange.levelCount = 1;
37+
barrier.subresourceRange.baseArrayLayer = 0;
38+
barrier.subresourceRange.layerCount = computeImageLayerCount(image.desc.type);
39+
return barrier;
40+
}
41+
42+
void issueBarriersCommand(const VkCommandBuffer commandBuffer,
43+
const std::vector<VkImageMemoryBarrier>& imageBarriers,
44+
const std::vector<VkBufferMemoryBarrier>& memoryBarriers) {
45+
46+
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr,
47+
(uint32_t)memoryBarriers.size(), memoryBarriers.data(), (uint32_t)imageBarriers.size(), imageBarriers.data());
48+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
#include "pch.h"
3+
#include <vulkan/vulkan.h>
4+
#include "Resources.h"
5+
6+
VkBufferMemoryBarrier createBufferBarrier(const Buffer& buffer,
7+
const VkAccessFlagBits srcAccess, const VkAccessFlagBits dstAccess);
8+
9+
VkImageMemoryBarrier createImageBarrier(const Image& image, const VkAccessFlags dstAccess,
10+
const VkImageLayout newLayout, const size_t mipLevel);
11+
12+
void issueBarriersCommand(const VkCommandBuffer commandBuffer,
13+
const std::vector<VkImageMemoryBarrier>& imageBarriers,
14+
const std::vector<VkBufferMemoryBarrier>& memoryBarriers);

Plain/src/Runtime/Rendering/Backend/VulkanImage.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,13 @@ VkImage createVulkanImage(const ImageDescription& desc, const bool isTransferTar
167167

168168
std::vector<VkImageLayout> createInitialImageLayouts(const uint32_t mipCount) {
169169
return std::vector<VkImageLayout>(mipCount, VK_IMAGE_LAYOUT_UNDEFINED);
170+
}
171+
172+
VkImageAspectFlags getVkImageAspectFlags(const VkFormat format) {
173+
if (isVulkanDepthFormat(format)) {
174+
return VK_IMAGE_ASPECT_DEPTH_BIT;
175+
}
176+
else {
177+
return VK_IMAGE_ASPECT_COLOR_BIT;
178+
}
170179
}

0 commit comments

Comments
 (0)