builds now with VCPKG and MSAA works
This commit is contained in:
@@ -33,6 +33,14 @@ Framebuffer::Framebuffer(PGraphics graphics, PRenderPass renderPass, Gfx::PRende
|
||||
width = std::max(width, vkColorAttachment->getWidth());
|
||||
height = std::max(height, vkColorAttachment->getHeight());
|
||||
}
|
||||
for (auto resolveAttachment : layout->resolveAttachments)
|
||||
{
|
||||
PTexture2D vkResolveAttachment = resolveAttachment->getTexture().cast<Texture2D>();
|
||||
attachments.add(vkResolveAttachment->getView());
|
||||
description.resolveAttachments[description.numResolveAttachments++] = vkResolveAttachment->getView();
|
||||
width = std::max(width, vkResolveAttachment->getWidth());
|
||||
height = std::max(height, vkResolveAttachment->getHeight());
|
||||
}
|
||||
if (layout->depthAttachment != nullptr)
|
||||
{
|
||||
PTexture2D vkDepthAttachment = layout->depthAttachment->getTexture().cast<Texture2D>();
|
||||
@@ -41,6 +49,14 @@ Framebuffer::Framebuffer(PGraphics graphics, PRenderPass renderPass, Gfx::PRende
|
||||
width = std::max(width, vkDepthAttachment->getWidth());
|
||||
height = std::max(height, vkDepthAttachment->getHeight());
|
||||
}
|
||||
if (layout->depthResolveAttachment != nullptr)
|
||||
{
|
||||
PTexture2D vkDepthAttachment = layout->depthResolveAttachment->getTexture().cast<Texture2D>();
|
||||
attachments.add(vkDepthAttachment->getView());
|
||||
description.depthResolveAttachment = vkDepthAttachment->getView();
|
||||
width = std::max(width, vkDepthAttachment->getWidth());
|
||||
height = std::max(height, vkDepthAttachment->getHeight());
|
||||
}
|
||||
VkFramebufferCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
||||
@@ -12,9 +12,12 @@ struct FramebufferDescription
|
||||
{
|
||||
StaticArray<VkImageView, 16> inputAttachments;
|
||||
StaticArray<VkImageView, 16> colorAttachments;
|
||||
StaticArray<VkImageView, 16> resolveAttachments;
|
||||
VkImageView depthAttachment;
|
||||
VkImageView depthResolveAttachment;
|
||||
uint32 numInputAttachments;
|
||||
uint32 numColorAttachments;
|
||||
uint32 numResolveAttachments;
|
||||
};
|
||||
class Framebuffer
|
||||
{
|
||||
|
||||
@@ -237,6 +237,42 @@ Gfx::OPipelineLayout Graphics::createPipelineLayout(Gfx::PPipelineLayout baseLay
|
||||
return new PipelineLayout(this, baseLayout);
|
||||
}
|
||||
|
||||
void Graphics::resolveTexture(Gfx::PTexture source, Gfx::PTexture destination)
|
||||
{
|
||||
PTextureBase sourceTex = source.cast<TextureBase>();
|
||||
PTextureBase destinationTex = destination.cast<TextureBase>();
|
||||
VkImageResolve resolve = {
|
||||
.srcSubresource = VkImageSubresourceLayers {
|
||||
.aspectMask = sourceTex->getAspect(),
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcOffset = VkOffset3D {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.z = 0,
|
||||
},
|
||||
.dstSubresource = VkImageSubresourceLayers {
|
||||
.aspectMask = sourceTex->getAspect(),
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.dstOffset = VkOffset3D {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.z = 0,
|
||||
},
|
||||
.extent = VkExtent3D {
|
||||
.width = sourceTex->getWidth(),
|
||||
.height = sourceTex->getHeight(),
|
||||
.depth = sourceTex->getDepth(),
|
||||
},
|
||||
};
|
||||
vkCmdResolveImage(getGraphicsCommands()->getCommands()->getHandle(), sourceTex->getImage(), cast(sourceTex->getLayout()), destinationTex->getImage(), cast(destinationTex->getLayout()), 1, &resolve);
|
||||
}
|
||||
|
||||
void Graphics::vkCmdDrawMeshTasksEXT(VkCommandBuffer handle, uint32 groupX, uint32 groupY, uint32 groupZ)
|
||||
{
|
||||
cmdDrawMeshTasks(handle, groupX, groupY, groupZ);
|
||||
@@ -410,7 +446,7 @@ void Graphics::pickPhysicalDevice()
|
||||
{
|
||||
if (std::strcmp(VK_EXT_MESH_SHADER_EXTENSION_NAME, extensionProps[i].extensionName) == 0)
|
||||
{
|
||||
//meshShadingEnabled = true;
|
||||
meshShadingEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ public:
|
||||
virtual Gfx::ODescriptorLayout createDescriptorLayout(const std::string& name = "") override;
|
||||
virtual Gfx::OPipelineLayout createPipelineLayout(Gfx::PPipelineLayout baseLayout = nullptr) override;
|
||||
|
||||
virtual void resolveTexture(Gfx::PTexture source, Gfx::PTexture destination) override;
|
||||
|
||||
void vkCmdDrawMeshTasksEXT(VkCommandBuffer handle, uint32 groupX, uint32 groupY, uint32 groupZ);
|
||||
protected:
|
||||
PFN_vkCmdDrawMeshTasksEXT cmdDrawMeshTasks;
|
||||
|
||||
@@ -17,15 +17,20 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::ORenderTargetLayout _layout, Gfx
|
||||
renderArea.offset.x = viewport->getOffsetX();
|
||||
renderArea.offset.y = viewport->getOffsetY();
|
||||
subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
|
||||
Array<VkAttachmentDescription> attachments;
|
||||
Array<VkAttachmentReference> inputRefs;
|
||||
Array<VkAttachmentReference> colorRefs;
|
||||
VkAttachmentReference depthRef;
|
||||
Array<VkAttachmentDescription2> attachments;
|
||||
Array<VkAttachmentReference2> inputRefs;
|
||||
Array<VkAttachmentReference2> colorRefs;
|
||||
Array<VkAttachmentReference2> resolveRefs;
|
||||
VkAttachmentReference2 depthRef;
|
||||
VkAttachmentReference2 depthResolveRef;
|
||||
|
||||
uint32 attachmentCounter = 0;
|
||||
for (auto& inputAttachment : layout->inputAttachments)
|
||||
{
|
||||
PTexture2D image = inputAttachment->getTexture().cast<Texture2D>();
|
||||
VkAttachmentDescription& desc = attachments.add() = {
|
||||
VkAttachmentDescription2& desc = attachments.add() = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.format = cast(image->getFormat()),
|
||||
.loadOp = cast(inputAttachment->getLoadOp()),
|
||||
@@ -33,7 +38,7 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::ORenderTargetLayout _layout, Gfx
|
||||
.stencilLoadOp = cast(inputAttachment->getStencilLoadOp()),
|
||||
.stencilStoreOp = cast(inputAttachment->getStencilStoreOp()),
|
||||
.initialLayout = image->isDepthStencil() ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.finalLayout = desc.initialLayout,
|
||||
.finalLayout = image->isDepthStencil() ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
inputRefs.add() = {
|
||||
@@ -44,6 +49,8 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::ORenderTargetLayout _layout, Gfx
|
||||
for (auto& colorAttachment : layout->colorAttachments)
|
||||
{
|
||||
attachments.add() = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.format = cast(colorAttachment->getFormat()),
|
||||
.samples = (VkSampleCountFlagBits)colorAttachment->getNumSamples(),
|
||||
@@ -62,6 +69,37 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::ORenderTargetLayout _layout, Gfx
|
||||
}
|
||||
|
||||
colorRefs.add() = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.pNext = nullptr,
|
||||
.attachment = attachmentCounter++,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
}
|
||||
for (auto& resolveAttachment : layout->resolveAttachments)
|
||||
{
|
||||
attachments.add() = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.format = cast(resolveAttachment->getFormat()),
|
||||
.samples = (VkSampleCountFlagBits)resolveAttachment->getNumSamples(),
|
||||
.loadOp = cast(resolveAttachment->getLoadOp()),
|
||||
.storeOp = cast(resolveAttachment->getStoreOp()),
|
||||
.stencilLoadOp = cast(resolveAttachment->getStencilLoadOp()),
|
||||
.stencilStoreOp = cast(resolveAttachment->getStencilStoreOp()),
|
||||
.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
VkClearValue& clearValue = clearValues.add();
|
||||
if (attachments.back().loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
{
|
||||
clearValue = cast(resolveAttachment->clear);
|
||||
}
|
||||
|
||||
resolveRefs.add() = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.pNext = nullptr,
|
||||
.attachment = attachmentCounter++,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
@@ -70,6 +108,8 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::ORenderTargetLayout _layout, Gfx
|
||||
{
|
||||
PTexture2D image = layout->depthAttachment->getTexture().cast<Texture2D>();
|
||||
attachments.add() = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.format = cast(image->getFormat()),
|
||||
.samples = (VkSampleCountFlagBits)image->getNumSamples(),
|
||||
@@ -80,28 +120,66 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::ORenderTargetLayout _layout, Gfx
|
||||
.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
|
||||
VkClearValue& clearValue = clearValues.add();
|
||||
if(attachments.back().loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
if (attachments.back().loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
{
|
||||
clearValue = cast(layout->depthAttachment->clear);
|
||||
}
|
||||
|
||||
depthRef = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.pNext = nullptr,
|
||||
.attachment = attachmentCounter++,
|
||||
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
}
|
||||
VkSubpassDescription subPassDesc = {
|
||||
if (layout->depthResolveAttachment != nullptr)
|
||||
{
|
||||
PTexture2D image = layout->depthResolveAttachment->getTexture().cast<Texture2D>();
|
||||
attachments.add() = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.format = cast(image->getFormat()),
|
||||
.samples = (VkSampleCountFlagBits)image->getNumSamples(),
|
||||
.loadOp = cast(layout->depthResolveAttachment->getLoadOp()),
|
||||
.storeOp = cast(layout->depthResolveAttachment->getStoreOp()),
|
||||
.stencilLoadOp = cast(layout->depthResolveAttachment->getStencilLoadOp()),
|
||||
.stencilStoreOp = cast(layout->depthResolveAttachment->getStencilStoreOp()),
|
||||
.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
depthResolveRef = {
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.pNext = nullptr,
|
||||
.attachment = attachmentCounter++,
|
||||
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
}
|
||||
|
||||
VkSubpassDescriptionDepthStencilResolve depthResolve = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE,
|
||||
.pNext = nullptr,
|
||||
.depthResolveMode = VK_RESOLVE_MODE_AVERAGE_BIT,
|
||||
.stencilResolveMode = VK_RESOLVE_MODE_AVERAGE_BIT,
|
||||
.pDepthStencilResolveAttachment = &depthResolveRef,
|
||||
};
|
||||
VkSubpassDescription2 subPassDesc = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2,
|
||||
.pNext = layout->depthResolveAttachment != nullptr ? &depthResolve : nullptr,
|
||||
.flags = 0,
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.inputAttachmentCount = (uint32)inputRefs.size(),
|
||||
.pInputAttachments = inputRefs.data(),
|
||||
.colorAttachmentCount = (uint32)colorRefs.size(),
|
||||
.pColorAttachments = colorRefs.data(),
|
||||
.pResolveAttachments = resolveRefs.size() > 0 ? resolveRefs.data() : nullptr,
|
||||
.pDepthStencilAttachment = &depthRef,
|
||||
};
|
||||
VkSubpassDependency dependency = {
|
||||
VkSubpassDependency2 dependency = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
|
||||
.pNext = nullptr,
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.dstSubpass = 0,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
@@ -110,8 +188,8 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::ORenderTargetLayout _layout, Gfx
|
||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
};
|
||||
|
||||
VkRenderPassCreateInfo info = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
VkRenderPassCreateInfo2 info = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2,
|
||||
.pNext = nullptr,
|
||||
.attachmentCount = (uint32)attachments.size(),
|
||||
.pAttachments = attachments.data(),
|
||||
@@ -121,7 +199,7 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::ORenderTargetLayout _layout, Gfx
|
||||
.pDependencies = &dependency,
|
||||
};
|
||||
|
||||
VK_CHECK(vkCreateRenderPass(graphics->getDevice(), &info, nullptr, &renderPass));
|
||||
VK_CHECK(vkCreateRenderPass2(graphics->getDevice(), &info, nullptr, &renderPass));
|
||||
}
|
||||
|
||||
RenderPass::~RenderPass()
|
||||
|
||||
@@ -71,6 +71,13 @@ TextureBase::TextureBase(PGraphics graphics, VkImageViewType viewType,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) == 0)
|
||||
{
|
||||
usage = usage
|
||||
| VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
}
|
||||
VkImageCreateInfo info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
@@ -86,10 +93,7 @@ TextureBase::TextureBase(PGraphics graphics, VkImageViewType viewType,
|
||||
.arrayLayers = arrayCount * layerCount,
|
||||
.samples = (VkSampleCountFlagBits)samples,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = usage
|
||||
| VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
.usage = usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.initialLayout = cast(layout),
|
||||
};
|
||||
@@ -112,7 +116,7 @@ TextureBase::TextureBase(PGraphics graphics, VkImageViewType viewType,
|
||||
};
|
||||
vkGetImageMemoryRequirements2(graphics->getDevice(), &reqInfo, &requirements);
|
||||
|
||||
allocation = pool->allocate(requirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, image);
|
||||
allocation = pool->allocate(requirements, createInfo.memoryProps, image);
|
||||
vkBindImageMemory(graphics->getDevice(), image, allocation->getHandle(), allocation->getOffset());
|
||||
}
|
||||
|
||||
@@ -158,6 +162,10 @@ TextureBase::TextureBase(PGraphics graphics, VkImageViewType viewType,
|
||||
{
|
||||
changeLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
else if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||
{
|
||||
changeLayout(Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL);
|
||||
|
||||
@@ -14,7 +14,18 @@ public:
|
||||
TextureBase(PGraphics graphics, VkImageViewType viewType,
|
||||
const TextureCreateInfo& createInfo, Gfx::QueueType& owner, VkImage existingImage = VK_NULL_HANDLE);
|
||||
virtual ~TextureBase();
|
||||
|
||||
uint32 getWidth() const
|
||||
{
|
||||
return width;
|
||||
}
|
||||
uint32 getHeight() const
|
||||
{
|
||||
return height;
|
||||
}
|
||||
uint32 getDepth() const
|
||||
{
|
||||
return depth;
|
||||
}
|
||||
constexpr VkImage getImage() const
|
||||
{
|
||||
return image;
|
||||
@@ -78,6 +89,7 @@ protected:
|
||||
uint8 ownsImage;
|
||||
friend class Graphics;
|
||||
};
|
||||
DEFINE_REF(TextureBase)
|
||||
|
||||
class Texture2D : public Gfx::Texture2D, public TextureBase
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@ void Window::beginFrame()
|
||||
{
|
||||
glfwPollEvents();
|
||||
vkAcquireNextImageKHR(graphics->getDevice(), swapchain, std::numeric_limits<uint64>::max(), imageAvailableSemaphores[currentSemaphoreIndex]->getHandle(), VK_NULL_HANDLE, ¤tImageIndex);
|
||||
swapChainTextures[currentImageIndex]->changeLayout(Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
swapChainTextures[currentImageIndex]->changeLayout(Gfx::SE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
graphics->getGraphicsCommands()->getCommands()->waitForSemaphore(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, imageAvailableSemaphores[currentSemaphoreIndex]);
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ void Window::createSwapChain()
|
||||
.imageColorSpace = format.colorSpace,
|
||||
.imageExtent = extent,
|
||||
.imageArrayLayers = 1,
|
||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.preTransform = capabilities.currentTransform,
|
||||
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
@@ -322,7 +322,7 @@ void Window::createSwapChain()
|
||||
.layers = 1,
|
||||
.elements = 1,
|
||||
.samples = 1,
|
||||
.usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
.usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
}, swapChainImages[i]);
|
||||
imageAvailableSemaphores[i] = new Semaphore(graphics);
|
||||
renderingDoneSemaphores[i] = new Semaphore(graphics);
|
||||
|
||||
Reference in New Issue
Block a user