mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
Merge pull request #1902 from nikeinikei/12.0-development
Improve vk render passes
This commit is contained in:
@@ -110,66 +110,10 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d
|
||||
|
||||
flushBatchedDraws();
|
||||
|
||||
if (!renderPassState.active)
|
||||
startRenderPass();
|
||||
|
||||
VkClearAttachment attachment{};
|
||||
|
||||
if (color.hasValue)
|
||||
{
|
||||
Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
|
||||
gammaCorrectColor(cf);
|
||||
|
||||
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
attachment.clearValue.color.float32[0] = static_cast<float>(cf.r);
|
||||
attachment.clearValue.color.float32[1] = static_cast<float>(cf.g);
|
||||
attachment.clearValue.color.float32[2] = static_cast<float>(cf.b);
|
||||
attachment.clearValue.color.float32[3] = static_cast<float>(cf.a);
|
||||
}
|
||||
|
||||
VkClearAttachment depthStencilAttachment{};
|
||||
|
||||
if (stencil.hasValue)
|
||||
{
|
||||
depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
depthStencilAttachment.clearValue.depthStencil.stencil = static_cast<uint32_t>(stencil.value);
|
||||
}
|
||||
if (depth.hasValue)
|
||||
{
|
||||
depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
depthStencilAttachment.clearValue.depthStencil.depth = static_cast<float>(depth.value);
|
||||
}
|
||||
|
||||
std::array<VkClearAttachment, 2> attachments = {
|
||||
attachment,
|
||||
depthStencilAttachment
|
||||
};
|
||||
|
||||
VkClearRect rect{};
|
||||
rect.layerCount = 1;
|
||||
rect.rect.extent.width = static_cast<uint32_t>(renderPassState.width);
|
||||
rect.rect.extent.height = static_cast<uint32_t>(renderPassState.height);
|
||||
|
||||
vkCmdClearAttachments(
|
||||
commandBuffers[currentFrame],
|
||||
static_cast<uint32_t>(attachments.size()), attachments.data(),
|
||||
1, &rect);
|
||||
}
|
||||
|
||||
void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth)
|
||||
{
|
||||
if (colors.empty() && !stencil.hasValue && !depth.hasValue)
|
||||
return;
|
||||
|
||||
flushBatchedDraws();
|
||||
|
||||
if (!renderPassState.active)
|
||||
startRenderPass();
|
||||
|
||||
std::vector<VkClearAttachment> attachments;
|
||||
for (const auto &color : colors)
|
||||
if (renderPassState.active)
|
||||
{
|
||||
VkClearAttachment attachment{};
|
||||
|
||||
if (color.hasValue)
|
||||
{
|
||||
Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
|
||||
@@ -181,33 +125,159 @@ void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt sten
|
||||
attachment.clearValue.color.float32[2] = static_cast<float>(cf.b);
|
||||
attachment.clearValue.color.float32[3] = static_cast<float>(cf.a);
|
||||
}
|
||||
attachments.push_back(attachment);
|
||||
|
||||
VkClearAttachment depthStencilAttachment{};
|
||||
|
||||
if (stencil.hasValue)
|
||||
{
|
||||
depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
depthStencilAttachment.clearValue.depthStencil.stencil = static_cast<uint32_t>(stencil.value);
|
||||
}
|
||||
if (depth.hasValue)
|
||||
{
|
||||
depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
depthStencilAttachment.clearValue.depthStencil.depth = static_cast<float>(depth.value);
|
||||
}
|
||||
|
||||
std::array<VkClearAttachment, 2> attachments = {
|
||||
attachment,
|
||||
depthStencilAttachment
|
||||
};
|
||||
|
||||
VkClearRect rect{};
|
||||
rect.layerCount = 1;
|
||||
rect.rect.extent.width = static_cast<uint32_t>(renderPassState.width);
|
||||
rect.rect.extent.height = static_cast<uint32_t>(renderPassState.height);
|
||||
|
||||
vkCmdClearAttachments(
|
||||
commandBuffers[currentFrame],
|
||||
static_cast<uint32_t>(attachments.size()), attachments.data(),
|
||||
1, &rect);
|
||||
}
|
||||
|
||||
VkClearAttachment depthStencilAttachment{};
|
||||
|
||||
if (stencil.hasValue)
|
||||
else
|
||||
{
|
||||
depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
depthStencilAttachment.clearValue.depthStencil.stencil = static_cast<uint32_t>(stencil.value);
|
||||
if (color.hasValue)
|
||||
{
|
||||
renderPassState.renderPassConfiguration.colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
|
||||
Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
|
||||
gammaCorrectColor(cf);
|
||||
|
||||
renderPassState.clearColors[0].color.float32[0] = static_cast<float>(cf.r);
|
||||
renderPassState.clearColors[0].color.float32[1] = static_cast<float>(cf.g);
|
||||
renderPassState.clearColors[0].color.float32[2] = static_cast<float>(cf.b);
|
||||
renderPassState.clearColors[0].color.float32[3] = static_cast<float>(cf.a);
|
||||
}
|
||||
|
||||
if (depth.hasValue)
|
||||
{
|
||||
renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
renderPassState.clearColors[1].depthStencil.depth = static_cast<float>(depth.value);
|
||||
}
|
||||
|
||||
if (stencil.hasValue)
|
||||
{
|
||||
renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
renderPassState.clearColors[1].depthStencil.stencil = static_cast<uint32_t>(stencil.value);
|
||||
}
|
||||
|
||||
if (renderPassState.isWindow)
|
||||
{
|
||||
renderPassState.windowClearRequested = true;
|
||||
renderPassState.mainWindowClearColorValue = color;
|
||||
renderPassState.mainWindowClearDepthValue = depth;
|
||||
renderPassState.mainWindowClearStencilValue = stencil;
|
||||
}
|
||||
else
|
||||
startRenderPass();
|
||||
}
|
||||
if (depth.hasValue)
|
||||
}
|
||||
|
||||
void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth)
|
||||
{
|
||||
if (colors.empty() && !stencil.hasValue && !depth.hasValue)
|
||||
return;
|
||||
|
||||
flushBatchedDraws();
|
||||
|
||||
if (renderPassState.active)
|
||||
{
|
||||
depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
depthStencilAttachment.clearValue.depthStencil.depth = static_cast<float>(depth.value);
|
||||
std::vector<VkClearAttachment> attachments;
|
||||
for (const auto &color : colors)
|
||||
{
|
||||
VkClearAttachment attachment{};
|
||||
if (color.hasValue)
|
||||
{
|
||||
Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
|
||||
gammaCorrectColor(cf);
|
||||
|
||||
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
attachment.clearValue.color.float32[0] = static_cast<float>(cf.r);
|
||||
attachment.clearValue.color.float32[1] = static_cast<float>(cf.g);
|
||||
attachment.clearValue.color.float32[2] = static_cast<float>(cf.b);
|
||||
attachment.clearValue.color.float32[3] = static_cast<float>(cf.a);
|
||||
}
|
||||
attachments.push_back(attachment);
|
||||
}
|
||||
|
||||
VkClearAttachment depthStencilAttachment{};
|
||||
|
||||
if (stencil.hasValue)
|
||||
{
|
||||
depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
depthStencilAttachment.clearValue.depthStencil.stencil = static_cast<uint32_t>(stencil.value);
|
||||
}
|
||||
if (depth.hasValue)
|
||||
{
|
||||
depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
depthStencilAttachment.clearValue.depthStencil.depth = static_cast<float>(depth.value);
|
||||
}
|
||||
|
||||
attachments.push_back(depthStencilAttachment);
|
||||
|
||||
VkClearRect rect{};
|
||||
rect.layerCount = 1;
|
||||
rect.rect.extent.width = static_cast<uint32_t>(renderPassState.width);
|
||||
rect.rect.extent.height = static_cast<uint32_t>(renderPassState.height);
|
||||
|
||||
vkCmdClearAttachments(
|
||||
commandBuffers[currentFrame],
|
||||
static_cast<uint32_t>(attachments.size()), attachments.data(),
|
||||
1, &rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < colors.size(); i++)
|
||||
{
|
||||
if (colors[i].hasValue)
|
||||
{
|
||||
renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
|
||||
attachments.push_back(depthStencilAttachment);
|
||||
auto &color = colors[i];
|
||||
Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a);
|
||||
gammaCorrectColor(cf);
|
||||
|
||||
VkClearRect rect{};
|
||||
rect.layerCount = 1;
|
||||
rect.rect.extent.width = static_cast<uint32_t>(renderPassState.width);
|
||||
rect.rect.extent.height = static_cast<uint32_t>(renderPassState.height);
|
||||
renderPassState.clearColors[i].color.float32[0] = static_cast<float>(cf.r);
|
||||
renderPassState.clearColors[i].color.float32[1] = static_cast<float>(cf.g);
|
||||
renderPassState.clearColors[i].color.float32[2] = static_cast<float>(cf.b);
|
||||
renderPassState.clearColors[i].color.float32[3] = static_cast<float>(cf.a);
|
||||
}
|
||||
}
|
||||
|
||||
vkCmdClearAttachments(
|
||||
commandBuffers[currentFrame],
|
||||
static_cast<uint32_t>(attachments.size()), attachments.data(),
|
||||
1, &rect);
|
||||
if (depth.hasValue)
|
||||
{
|
||||
renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
renderPassState.clearColors[colors.size()].depthStencil.depth = static_cast<float>(depth.value);
|
||||
}
|
||||
|
||||
if (stencil.hasValue)
|
||||
{
|
||||
renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
renderPassState.clearColors[colors.size()].depthStencil.stencil = static_cast<uint32_t>(stencil.value);
|
||||
}
|
||||
|
||||
startRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
|
||||
@@ -215,40 +285,18 @@ void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
|
||||
if (renderPassState.active)
|
||||
endRenderPass();
|
||||
|
||||
if (renderPassState.useConfigurations)
|
||||
{
|
||||
auto & renderPassConfiguration = renderPassState.renderPassConfiguration;
|
||||
auto &renderPassConfiguration = renderPassState.renderPassConfiguration;
|
||||
|
||||
for (size_t i = 0; i < colorbuffers.size(); i++)
|
||||
renderPassConfiguration.colorAttachments[i].discard = colorbuffers[i];
|
||||
renderPassConfiguration.staticData.depthAttachment.discard = depthstencil;
|
||||
for (size_t i = 0; i < colorbuffers.size(); i++)
|
||||
{
|
||||
if (colorbuffers[i])
|
||||
renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
else
|
||||
|
||||
if (depthstencil)
|
||||
{
|
||||
RenderPassConfiguration renderPassConfiguration{};
|
||||
renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, colorbuffers[0], msaaSamples });
|
||||
renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), depthstencil, msaaSamples };
|
||||
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
|
||||
renderPassConfiguration.staticData.resolve = false;
|
||||
else
|
||||
renderPassConfiguration.staticData.resolve = true;
|
||||
|
||||
FramebufferConfiguration framebufferConfiguration{};
|
||||
framebufferConfiguration.staticData.depthView = depthImageView;
|
||||
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
|
||||
{
|
||||
framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex));
|
||||
framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
framebufferConfiguration.colorViews.push_back(colorImageView);
|
||||
framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex);
|
||||
}
|
||||
|
||||
renderPassState.useConfigurations = true;
|
||||
renderPassState.renderPassConfiguration = renderPassConfiguration;
|
||||
renderPassState.framebufferConfiguration = framebufferConfiguration;
|
||||
renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
|
||||
startRenderPass();
|
||||
@@ -422,6 +470,9 @@ void Graphics::present(void *screenshotCallbackdata)
|
||||
if (isRenderTargetActive())
|
||||
throw love::Exception("present cannot be called while a render target is active.");
|
||||
|
||||
if (!renderPassState.active && renderPassState.windowClearRequested)
|
||||
startRenderPass();
|
||||
|
||||
deprecations.draw(this);
|
||||
|
||||
submitGpuCommands(true, screenshotCallbackdata);
|
||||
@@ -493,6 +544,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
createSurface();
|
||||
pickPhysicalDevice();
|
||||
createLogicalDevice();
|
||||
createPipelineCache();
|
||||
initVMA();
|
||||
initCapabilities();
|
||||
createSwapChain();
|
||||
@@ -502,8 +554,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
createColorResources();
|
||||
createDepthResources();
|
||||
transitionColorDepthLayouts = true;
|
||||
createDefaultRenderPass();
|
||||
createDefaultFramebuffers();
|
||||
createCommandPool();
|
||||
createCommandBuffers();
|
||||
|
||||
@@ -580,9 +630,9 @@ void Graphics::initCapabilities()
|
||||
capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = properties.limits.maxImageDimensionCube;
|
||||
capabilities.limits[LIMIT_TEXEL_BUFFER_SIZE] = properties.limits.maxTexelBufferElements;
|
||||
capabilities.limits[LIMIT_SHADER_STORAGE_BUFFER_SIZE] = properties.limits.maxStorageBufferRange;
|
||||
capabilities.limits[LIMIT_THREADGROUPS_X] = properties.limits.maxComputeWorkGroupSize[0];
|
||||
capabilities.limits[LIMIT_THREADGROUPS_Y] = properties.limits.maxComputeWorkGroupSize[1];
|
||||
capabilities.limits[LIMIT_THREADGROUPS_Z] = properties.limits.maxComputeWorkGroupSize[2];
|
||||
capabilities.limits[LIMIT_THREADGROUPS_X] = properties.limits.maxComputeWorkGroupCount[0];
|
||||
capabilities.limits[LIMIT_THREADGROUPS_Y] = properties.limits.maxComputeWorkGroupCount[1];
|
||||
capabilities.limits[LIMIT_THREADGROUPS_Z] = properties.limits.maxComputeWorkGroupCount[2];
|
||||
capabilities.limits[LIMIT_RENDER_TARGETS] = properties.limits.maxColorAttachments;
|
||||
capabilities.limits[LIMIT_TEXTURE_MSAA] = static_cast<double>(getMsaaCount(64));
|
||||
capabilities.limits[LIMIT_ANISOTROPY] = properties.limits.maxSamplerAnisotropy;
|
||||
@@ -638,7 +688,7 @@ void Graphics::setFrontFaceWinding(Winding winding)
|
||||
|
||||
states.back().winding = winding;
|
||||
|
||||
if (optionalDeviceFeatures.extendedDynamicState)
|
||||
if (optionalDeviceExtensions.extendedDynamicState)
|
||||
vkCmdSetFrontFaceEXT(
|
||||
commandBuffers.at(currentFrame),
|
||||
Vulkan::getFrontFace(winding));
|
||||
@@ -875,7 +925,7 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val
|
||||
vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, readmask);
|
||||
vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, value);
|
||||
|
||||
if (optionalDeviceFeatures.extendedDynamicState)
|
||||
if (optionalDeviceExtensions.extendedDynamicState)
|
||||
vkCmdSetStencilOpEXT(
|
||||
commandBuffers.at(currentFrame),
|
||||
VK_STENCIL_FRONT_AND_BACK,
|
||||
@@ -893,7 +943,7 @@ void Graphics::setDepthMode(CompareMode compare, bool write)
|
||||
{
|
||||
flushBatchedDraws();
|
||||
|
||||
if (optionalDeviceFeatures.extendedDynamicState)
|
||||
if (optionalDeviceExtensions.extendedDynamicState)
|
||||
{
|
||||
vkCmdSetDepthCompareOpEXT(
|
||||
commandBuffers.at(currentFrame), Vulkan::getCompareOp(compare));
|
||||
@@ -1035,6 +1085,8 @@ graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size)
|
||||
|
||||
bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z)
|
||||
{
|
||||
usedShadersInFrame.insert(computeShader);
|
||||
|
||||
if (renderPassState.active)
|
||||
endRenderPass();
|
||||
|
||||
@@ -1050,6 +1102,8 @@ bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z)
|
||||
|
||||
bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer *indirectargs, size_t argsoffset)
|
||||
{
|
||||
usedShadersInFrame.insert(computeShader);
|
||||
|
||||
if (renderPassState.active)
|
||||
endRenderPass();
|
||||
|
||||
@@ -1094,7 +1148,7 @@ void Graphics::initDynamicState()
|
||||
vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.readMask);
|
||||
vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.value);
|
||||
|
||||
if (optionalDeviceFeatures.extendedDynamicState)
|
||||
if (optionalDeviceExtensions.extendedDynamicState)
|
||||
{
|
||||
vkCmdSetStencilOpEXT(
|
||||
commandBuffers.at(currentFrame),
|
||||
@@ -1176,6 +1230,8 @@ void Graphics::beginFrame()
|
||||
|
||||
Vulkan::resetShaderSwitches();
|
||||
|
||||
for (const auto shader : usedShadersInFrame)
|
||||
shader->newFrame();
|
||||
usedShadersInFrame.clear();
|
||||
}
|
||||
|
||||
@@ -1269,9 +1325,9 @@ graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData()
|
||||
return data;
|
||||
}
|
||||
|
||||
const OptionalDeviceFeatures &Graphics::getEnabledOptionalDeviceExtensions() const
|
||||
const OptionalDeviceExtensions &Graphics::getEnabledOptionalDeviceExtensions() const
|
||||
{
|
||||
return optionalDeviceFeatures;
|
||||
return optionalDeviceExtensions;
|
||||
}
|
||||
|
||||
static void checkOptionalInstanceExtensions(OptionalInstanceExtensions &ext)
|
||||
@@ -1401,6 +1457,7 @@ void Graphics::pickPhysicalDevice()
|
||||
deviceApiVersion = properties.apiVersion;
|
||||
|
||||
msaaSamples = getMsaaCount(requestedMsaa);
|
||||
depthStencilFormat = findDepthFormat();
|
||||
}
|
||||
|
||||
bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device)
|
||||
@@ -1498,7 +1555,7 @@ QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device)
|
||||
return indices;
|
||||
}
|
||||
|
||||
static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceFeatures &optionalDeviceFeatures)
|
||||
static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceExtensions &optionalDeviceExtensions)
|
||||
{
|
||||
uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
|
||||
@@ -1509,19 +1566,17 @@ static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, Option
|
||||
for (const auto &extension : availableExtensions)
|
||||
{
|
||||
if (strcmp(extension.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0)
|
||||
optionalDeviceFeatures.extendedDynamicState = true;
|
||||
optionalDeviceExtensions.extendedDynamicState = true;
|
||||
if (strcmp(extension.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
|
||||
optionalDeviceFeatures.memoryRequirements2 = true;
|
||||
optionalDeviceExtensions.memoryRequirements2 = true;
|
||||
if (strcmp(extension.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
|
||||
optionalDeviceFeatures.dedicatedAllocation = true;
|
||||
optionalDeviceExtensions.dedicatedAllocation = true;
|
||||
if (strcmp(extension.extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0)
|
||||
optionalDeviceFeatures.bufferDeviceAddress = true;
|
||||
if (strcmp(extension.extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
|
||||
optionalDeviceFeatures.memoryBudget = true;
|
||||
optionalDeviceExtensions.memoryBudget = true;
|
||||
if (strcmp(extension.extensionName, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) == 0)
|
||||
optionalDeviceFeatures.shaderFloatControls = true;
|
||||
optionalDeviceExtensions.shaderFloatControls = true;
|
||||
if (strcmp(extension.extensionName, VK_KHR_SPIRV_1_4_EXTENSION_NAME) == 0)
|
||||
optionalDeviceFeatures.spirv14 = true;
|
||||
optionalDeviceExtensions.spirv14 = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1546,22 +1601,20 @@ void Graphics::createLogicalDevice()
|
||||
queueCreateInfos.push_back(queueCreateInfo);
|
||||
}
|
||||
|
||||
findOptionalDeviceExtensions(physicalDevice, optionalDeviceFeatures);
|
||||
findOptionalDeviceExtensions(physicalDevice, optionalDeviceExtensions);
|
||||
|
||||
// sanity check for dependencies.
|
||||
|
||||
if (optionalDeviceFeatures.extendedDynamicState && !optionalInstanceExtensions.physicalDeviceProperties2)
|
||||
optionalDeviceFeatures.extendedDynamicState = false;
|
||||
if (optionalDeviceFeatures.dedicatedAllocation && !optionalDeviceFeatures.memoryRequirements2)
|
||||
optionalDeviceFeatures.dedicatedAllocation = false;
|
||||
if (optionalDeviceFeatures.bufferDeviceAddress && !optionalInstanceExtensions.physicalDeviceProperties2)
|
||||
optionalDeviceFeatures.bufferDeviceAddress = false;
|
||||
if (optionalDeviceFeatures.memoryBudget && !optionalInstanceExtensions.physicalDeviceProperties2)
|
||||
optionalDeviceFeatures.memoryBudget = false;
|
||||
if (optionalDeviceFeatures.spirv14 && !optionalDeviceFeatures.shaderFloatControls)
|
||||
optionalDeviceFeatures.spirv14 = false;
|
||||
if (optionalDeviceFeatures.spirv14 && deviceApiVersion < VK_API_VERSION_1_1)
|
||||
optionalDeviceFeatures.spirv14 = false;
|
||||
if (optionalDeviceExtensions.extendedDynamicState && !optionalInstanceExtensions.physicalDeviceProperties2)
|
||||
optionalDeviceExtensions.extendedDynamicState = false;
|
||||
if (optionalDeviceExtensions.dedicatedAllocation && !optionalDeviceExtensions.memoryRequirements2)
|
||||
optionalDeviceExtensions.dedicatedAllocation = false;
|
||||
if (optionalDeviceExtensions.memoryBudget && !optionalInstanceExtensions.physicalDeviceProperties2)
|
||||
optionalDeviceExtensions.memoryBudget = false;
|
||||
if (optionalDeviceExtensions.spirv14 && !optionalDeviceExtensions.shaderFloatControls)
|
||||
optionalDeviceExtensions.spirv14 = false;
|
||||
if (optionalDeviceExtensions.spirv14 && deviceApiVersion < VK_API_VERSION_1_1)
|
||||
optionalDeviceExtensions.spirv14 = false;
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||
deviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||
@@ -1574,19 +1627,17 @@ void Graphics::createLogicalDevice()
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
|
||||
std::vector<const char*> enabledExtensions(deviceExtensions.begin(), deviceExtensions.end());
|
||||
if (optionalDeviceFeatures.extendedDynamicState)
|
||||
if (optionalDeviceExtensions.extendedDynamicState)
|
||||
enabledExtensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||
if (optionalDeviceFeatures.memoryRequirements2)
|
||||
if (optionalDeviceExtensions.memoryRequirements2)
|
||||
enabledExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
||||
if (optionalDeviceFeatures.dedicatedAllocation)
|
||||
if (optionalDeviceExtensions.dedicatedAllocation)
|
||||
enabledExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
|
||||
if (optionalDeviceFeatures.bufferDeviceAddress)
|
||||
enabledExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||
if (optionalDeviceFeatures.memoryBudget)
|
||||
if (optionalDeviceExtensions.memoryBudget)
|
||||
enabledExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
|
||||
if (optionalDeviceFeatures.shaderFloatControls)
|
||||
if (optionalDeviceExtensions.shaderFloatControls)
|
||||
enabledExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
|
||||
if (optionalDeviceFeatures.spirv14)
|
||||
if (optionalDeviceExtensions.spirv14)
|
||||
enabledExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME);
|
||||
if (deviceApiVersion >= VK_API_VERSION_1_1)
|
||||
enabledExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
|
||||
@@ -1602,7 +1653,7 @@ void Graphics::createLogicalDevice()
|
||||
|
||||
VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures{};
|
||||
extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
|
||||
extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceFeatures.extendedDynamicState);
|
||||
extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceExtensions.extendedDynamicState);
|
||||
extendedDynamicStateFeatures.pNext = nullptr;
|
||||
|
||||
createInfo.pNext = &extendedDynamicStateFeatures;
|
||||
@@ -1616,6 +1667,15 @@ void Graphics::createLogicalDevice()
|
||||
vkGetDeviceQueue(device, indices.presentFamily.value, 0, &presentQueue);
|
||||
}
|
||||
|
||||
void Graphics::createPipelineCache()
|
||||
{
|
||||
VkPipelineCacheCreateInfo cacheInfo{};
|
||||
cacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
||||
|
||||
if (vkCreatePipelineCache(device, &cacheInfo, nullptr, &pipelineCache) != VK_SUCCESS)
|
||||
throw love::Exception("could not create pipeline cache");
|
||||
}
|
||||
|
||||
void Graphics::initVMA()
|
||||
{
|
||||
VmaAllocatorCreateInfo allocatorCreateInfo = {};
|
||||
@@ -1657,9 +1717,9 @@ void Graphics::initVMA()
|
||||
allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;
|
||||
|
||||
allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
|
||||
if (optionalDeviceFeatures.dedicatedAllocation)
|
||||
if (optionalDeviceExtensions.dedicatedAllocation)
|
||||
allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
|
||||
if (optionalDeviceFeatures.memoryBudget)
|
||||
if (optionalDeviceExtensions.memoryBudget)
|
||||
allocatorCreateInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
|
||||
|
||||
if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS)
|
||||
@@ -1966,40 +2026,6 @@ void Graphics::createScreenshotCallbackBuffers()
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::createDefaultRenderPass()
|
||||
{
|
||||
RenderPassConfiguration renderPassConfiguration{};
|
||||
renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, false, msaaSamples });
|
||||
renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), false, msaaSamples };
|
||||
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
|
||||
renderPassConfiguration.staticData.resolve = false;
|
||||
else
|
||||
renderPassConfiguration.staticData.resolve = true;
|
||||
defaultRenderPass = createRenderPass(renderPassConfiguration);
|
||||
}
|
||||
|
||||
void Graphics::createDefaultFramebuffers()
|
||||
{
|
||||
defaultFramebuffers.clear();
|
||||
|
||||
for (const auto view : swapChainImageViews)
|
||||
{
|
||||
FramebufferConfiguration configuration{};
|
||||
configuration.staticData.renderPass = defaultRenderPass;
|
||||
configuration.staticData.width = swapChainExtent.width;
|
||||
configuration.staticData.height = swapChainExtent.height;
|
||||
configuration.staticData.depthView = depthImageView;
|
||||
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
|
||||
configuration.colorViews.push_back(view);
|
||||
else
|
||||
{
|
||||
configuration.colorViews.push_back(colorImageView);
|
||||
configuration.staticData.resolveView = view;
|
||||
}
|
||||
defaultFramebuffers.push_back(createFramebuffer(configuration));
|
||||
}
|
||||
}
|
||||
|
||||
VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration &configuration)
|
||||
{
|
||||
std::vector<VkImageView> attachments;
|
||||
@@ -2081,10 +2107,7 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
|
||||
VkAttachmentDescription colorDescription{};
|
||||
colorDescription.format = colorAttachment.format;
|
||||
colorDescription.samples = colorAttachment.msaaSamples;
|
||||
if (colorAttachment.discard)
|
||||
colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
else
|
||||
colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
colorDescription.loadOp = colorAttachment.loadOp;
|
||||
colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
@@ -2097,24 +2120,18 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
|
||||
subPass.pColorAttachments = colorAttachmentRefs.data();
|
||||
|
||||
VkAttachmentReference depthStencilAttachmentRef{};
|
||||
if (configuration.staticData.depthAttachment.format != VK_FORMAT_UNDEFINED)
|
||||
if (configuration.staticData.depthStencilAttachment.format != VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
depthStencilAttachmentRef.attachment = attachment++;
|
||||
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
subPass.pDepthStencilAttachment = &depthStencilAttachmentRef;
|
||||
|
||||
VkAttachmentDescription depthStencilAttachment{};
|
||||
depthStencilAttachment.format = configuration.staticData.depthAttachment.format;
|
||||
depthStencilAttachment.samples = configuration.staticData.depthAttachment.msaaSamples;
|
||||
if (configuration.staticData.depthAttachment.discard)
|
||||
depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
else
|
||||
depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthStencilAttachment.format = configuration.staticData.depthStencilAttachment.format;
|
||||
depthStencilAttachment.samples = configuration.staticData.depthStencilAttachment.msaaSamples;
|
||||
depthStencilAttachment.loadOp = configuration.staticData.depthStencilAttachment.depthLoadOp;
|
||||
depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
if (configuration.staticData.depthAttachment.discard)
|
||||
depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
else
|
||||
depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthStencilAttachment.stencilLoadOp = configuration.staticData.depthStencilAttachment.stencilLoadOp;
|
||||
depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
@@ -2174,6 +2191,23 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
|
||||
return renderPass;
|
||||
}
|
||||
|
||||
VkRenderPass Graphics::getRenderPass(RenderPassConfiguration &configuration)
|
||||
{
|
||||
VkRenderPass renderPass;
|
||||
auto it = renderPasses.find(configuration);
|
||||
if (it != renderPasses.end())
|
||||
renderPass = it->second;
|
||||
else
|
||||
{
|
||||
renderPass = createRenderPass(configuration);
|
||||
renderPasses[configuration] = renderPass;
|
||||
}
|
||||
|
||||
renderPassUsages[renderPass] = true;
|
||||
|
||||
return renderPass;
|
||||
}
|
||||
|
||||
bool Graphics::usesConstantVertexColor(const VertexAttributes &vertexAttributes)
|
||||
{
|
||||
return !!(vertexAttributes.enableBits & (1u << ATTRIB_COLOR));
|
||||
@@ -2259,7 +2293,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
|
||||
if (!renderPassState.active)
|
||||
startRenderPass();
|
||||
|
||||
Shader::current->attach();
|
||||
usedShadersInFrame.insert((dynamic_cast<Shader*>(Shader::current)));
|
||||
|
||||
GraphicsPipelineConfiguration configuration{};
|
||||
|
||||
@@ -2273,7 +2307,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
|
||||
configuration.numColorAttachments = renderPassState.numColorAttachments;
|
||||
configuration.primitiveType = primitiveType;
|
||||
|
||||
if (optionalDeviceFeatures.extendedDynamicState)
|
||||
if (optionalDeviceExtensions.extendedDynamicState)
|
||||
vkCmdSetCullModeEXT(commandBuffers.at(currentFrame), Vulkan::getCullMode(cullmode));
|
||||
else
|
||||
{
|
||||
@@ -2316,20 +2350,54 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
|
||||
|
||||
void Graphics::setDefaultRenderPass()
|
||||
{
|
||||
uint32_t numClearValues = 2;
|
||||
renderPassState.clearColors.resize(numClearValues);
|
||||
|
||||
renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
renderPassState.beginInfo.renderPass = defaultRenderPass;
|
||||
renderPassState.beginInfo.framebuffer = defaultFramebuffers[imageIndex];
|
||||
renderPassState.beginInfo.renderPass = VK_NULL_HANDLE;
|
||||
renderPassState.beginInfo.framebuffer = VK_NULL_HANDLE;
|
||||
renderPassState.beginInfo.renderArea.offset = { 0, 0 };
|
||||
renderPassState.beginInfo.renderArea.extent = swapChainExtent;
|
||||
renderPassState.beginInfo.clearValueCount = 0;
|
||||
renderPassState.beginInfo.clearValueCount = numClearValues;
|
||||
renderPassState.beginInfo.pClearValues = renderPassState.clearColors.data();
|
||||
|
||||
renderPassState.useConfigurations = false;
|
||||
renderPassState.isWindow = true;
|
||||
renderPassState.pipeline = VK_NULL_HANDLE;
|
||||
renderPassState.width = static_cast<float>(swapChainExtent.width);
|
||||
renderPassState.height = static_cast<float>(swapChainExtent.height);
|
||||
renderPassState.msaa = msaaSamples;
|
||||
renderPassState.numColorAttachments = 1;
|
||||
renderPassState.transitionImages.clear();
|
||||
|
||||
RenderPassConfiguration renderPassConfiguration{};
|
||||
renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples });
|
||||
renderPassConfiguration.staticData.depthStencilAttachment = { depthStencilFormat, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples };
|
||||
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
|
||||
renderPassConfiguration.staticData.resolve = false;
|
||||
else
|
||||
renderPassConfiguration.staticData.resolve = true;
|
||||
|
||||
FramebufferConfiguration framebufferConfiguration{};
|
||||
framebufferConfiguration.staticData.depthView = depthImageView;
|
||||
framebufferConfiguration.staticData.width = swapChainExtent.width;
|
||||
framebufferConfiguration.staticData.height = swapChainExtent.height;
|
||||
|
||||
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
|
||||
{
|
||||
framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex));
|
||||
framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
framebufferConfiguration.colorViews.push_back(colorImageView);
|
||||
framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex);
|
||||
}
|
||||
|
||||
renderPassState.renderPassConfiguration = std::move(renderPassConfiguration);
|
||||
renderPassState.framebufferConfiguration = std::move(framebufferConfiguration);
|
||||
|
||||
if (renderPassState.windowClearRequested)
|
||||
clear(renderPassState.mainWindowClearColorValue, renderPassState.mainWindowClearStencilValue, renderPassState.mainWindowClearDepthValue);
|
||||
}
|
||||
|
||||
void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture)
|
||||
@@ -2341,14 +2409,14 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
|
||||
for (const auto &color : rts.colors)
|
||||
renderPassConfiguration.colorAttachments.push_back({
|
||||
Vulkan::getTextureFormat(color.texture->getPixelFormat(), isPixelFormatSRGB(color.texture->getPixelFormat())).internalFormat,
|
||||
false,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
dynamic_cast<Texture*>(color.texture)->getMsaaSamples() });
|
||||
if (rts.depthStencil.texture != nullptr)
|
||||
if (rts.depthStencil.texture != nullptr)
|
||||
renderPassConfiguration.staticData.depthAttachment = {
|
||||
Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat,
|
||||
false,
|
||||
dynamic_cast<Texture*>(rts.depthStencil.texture)->getMsaaSamples() };
|
||||
renderPassConfiguration.staticData.depthStencilAttachment = {
|
||||
Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
dynamic_cast<Texture*>(rts.depthStencil.texture)->getMsaaSamples() };
|
||||
|
||||
FramebufferConfiguration configuration{};
|
||||
|
||||
@@ -2365,15 +2433,19 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
|
||||
configuration.staticData.width = static_cast<uint32_t>(pixelw);
|
||||
configuration.staticData.height = static_cast<uint32_t>(pixelh);
|
||||
|
||||
uint32_t numClearValues = static_cast<uint32_t>(rts.colors.size() + 1);
|
||||
renderPassState.clearColors.resize(numClearValues);
|
||||
|
||||
renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
renderPassState.beginInfo.renderPass = VK_NULL_HANDLE;
|
||||
renderPassState.beginInfo.framebuffer = VK_NULL_HANDLE;
|
||||
renderPassState.beginInfo.renderArea.offset = {0, 0};
|
||||
renderPassState.beginInfo.renderArea.extent.width = static_cast<uint32_t>(pixelw);
|
||||
renderPassState.beginInfo.renderArea.extent.height = static_cast<uint32_t>(pixelh);
|
||||
renderPassState.beginInfo.clearValueCount = 0;
|
||||
renderPassState.beginInfo.clearValueCount = numClearValues;
|
||||
renderPassState.beginInfo.pClearValues = renderPassState.clearColors.data();
|
||||
|
||||
renderPassState.useConfigurations = true;
|
||||
renderPassState.isWindow = false;
|
||||
renderPassState.renderPassConfiguration = renderPassConfiguration;
|
||||
renderPassState.framebufferConfiguration = configuration;
|
||||
renderPassState.pipeline = VK_NULL_HANDLE;
|
||||
@@ -2388,6 +2460,9 @@ void Graphics::startRenderPass()
|
||||
{
|
||||
renderPassState.active = true;
|
||||
|
||||
if (renderPassState.isWindow && renderPassState.windowClearRequested)
|
||||
renderPassState.windowClearRequested = false;
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
@@ -2398,26 +2473,10 @@ void Graphics::startRenderPass()
|
||||
|
||||
vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport);
|
||||
|
||||
if (renderPassState.useConfigurations)
|
||||
{
|
||||
auto &renderPassConfiguration = renderPassState.renderPassConfiguration;
|
||||
VkRenderPass renderPass;
|
||||
auto it = renderPasses.find(renderPassConfiguration);
|
||||
if (it != renderPasses.end())
|
||||
renderPass = it->second;
|
||||
else
|
||||
{
|
||||
renderPass = createRenderPass(renderPassConfiguration);
|
||||
renderPasses[renderPassConfiguration] = renderPass;
|
||||
}
|
||||
renderPassState.beginInfo.renderPass = renderPass;
|
||||
renderPassState.beginInfo.renderPass = getRenderPass(renderPassState.renderPassConfiguration);
|
||||
|
||||
renderPassUsages[renderPass] = true;
|
||||
|
||||
auto &framebufferConfiguration = renderPassState.framebufferConfiguration;
|
||||
framebufferConfiguration.staticData.renderPass = renderPass;
|
||||
renderPassState.beginInfo.framebuffer = getFramebuffer(framebufferConfiguration);
|
||||
}
|
||||
renderPassState.framebufferConfiguration.staticData.renderPass = renderPassState.beginInfo.renderPass;
|
||||
renderPassState.beginInfo.framebuffer = getFramebuffer(renderPassState.framebufferConfiguration);
|
||||
|
||||
for (const auto &image : renderPassState.transitionImages)
|
||||
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
@@ -2433,6 +2492,12 @@ void Graphics::endRenderPass()
|
||||
|
||||
for (const auto &image : renderPassState.transitionImages)
|
||||
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
for (auto &colorAttachment : renderPassState.renderPassConfiguration.colorAttachments)
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
|
||||
renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
}
|
||||
|
||||
VkSampler Graphics::createSampler(const SamplerState &samplerState)
|
||||
@@ -2523,11 +2588,6 @@ void Graphics::setComputeShader(Shader *shader)
|
||||
computeShader = shader;
|
||||
}
|
||||
|
||||
std::set<Shader*> &Graphics::getUsedShadersInFrame()
|
||||
{
|
||||
return usedShadersInFrame;
|
||||
}
|
||||
|
||||
VkSampler Graphics::getCachedSampler(const SamplerState &samplerState)
|
||||
{
|
||||
auto samplerkey = samplerState.toKey();
|
||||
@@ -2577,7 +2637,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterizer.polygonMode = Vulkan::getPolygonMode(configuration.wireFrame);
|
||||
rasterizer.lineWidth = 1.0f;
|
||||
if (!optionalDeviceFeatures.extendedDynamicState)
|
||||
if (!optionalDeviceExtensions.extendedDynamicState)
|
||||
{
|
||||
rasterizer.cullMode = Vulkan::getCullMode(configuration.dynamicState.cullmode);
|
||||
rasterizer.frontFace = Vulkan::getFrontFace(configuration.dynamicState.winding);
|
||||
@@ -2596,7 +2656,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencil{};
|
||||
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
depthStencil.depthTestEnable = VK_TRUE;
|
||||
if (!optionalDeviceFeatures.extendedDynamicState)
|
||||
if (!optionalDeviceExtensions.extendedDynamicState)
|
||||
{
|
||||
depthStencil.depthWriteEnable = Vulkan::getBool(configuration.dynamicState.depthState.write);
|
||||
depthStencil.depthCompareOp = Vulkan::getCompareOp(configuration.dynamicState.depthState.compare);
|
||||
@@ -2607,7 +2667,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi
|
||||
|
||||
depthStencil.stencilTestEnable = VK_TRUE;
|
||||
|
||||
if (!optionalDeviceFeatures.extendedDynamicState)
|
||||
if (!optionalDeviceExtensions.extendedDynamicState)
|
||||
{
|
||||
depthStencil.front.failOp = VK_STENCIL_OP_KEEP;
|
||||
depthStencil.front.passOp = Vulkan::getStencilOp(configuration.dynamicState.stencilAction);
|
||||
@@ -2647,7 +2707,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi
|
||||
|
||||
std::vector<VkDynamicState> dynamicStates;
|
||||
|
||||
if (optionalDeviceFeatures.extendedDynamicState)
|
||||
if (optionalDeviceExtensions.extendedDynamicState)
|
||||
dynamicStates = {
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
@@ -2691,7 +2751,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi
|
||||
pipelineInfo.renderPass = configuration.renderPass;
|
||||
|
||||
VkPipeline graphicsPipeline;
|
||||
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS)
|
||||
if (vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS)
|
||||
throw love::Exception("failed to create graphics pipeline");
|
||||
return graphicsPipeline;
|
||||
}
|
||||
@@ -2839,12 +2899,10 @@ VkFormat Graphics::findDepthFormat()
|
||||
|
||||
void Graphics::createDepthResources()
|
||||
{
|
||||
VkFormat depthAttachment = findDepthFormat();
|
||||
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = depthAttachment;
|
||||
imageInfo.format = depthStencilFormat;
|
||||
imageInfo.extent.width = swapChainExtent.width;
|
||||
imageInfo.extent.height = swapChainExtent.height;
|
||||
imageInfo.extent.depth = 1;
|
||||
@@ -2867,7 +2925,7 @@ void Graphics::createDepthResources()
|
||||
imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
imageViewInfo.image = depthImage;
|
||||
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
imageViewInfo.format = depthAttachment;
|
||||
imageViewInfo.format = depthStencilFormat;
|
||||
imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
@@ -2977,6 +3035,7 @@ void Graphics::cleanup()
|
||||
graphicsPipelines.clear();
|
||||
|
||||
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||
vkDestroyPipelineCache(device, pipelineCache, nullptr);
|
||||
vkDestroyDevice(device, nullptr);
|
||||
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
@@ -2989,9 +3048,6 @@ void Graphics::cleanupSwapChain()
|
||||
vmaDestroyBuffer(vmaAllocator, readbackBuffer.buffer, readbackBuffer.allocation);
|
||||
vmaDestroyImage(vmaAllocator, readbackBuffer.image, readbackBuffer.imageAllocation);
|
||||
}
|
||||
for (const auto &framebuffer : defaultFramebuffers)
|
||||
vkDestroyFramebuffer(device, framebuffer, nullptr);
|
||||
vkDestroyRenderPass(device, defaultRenderPass, nullptr);
|
||||
vkDestroyImageView(device, colorImageView, nullptr);
|
||||
vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation);
|
||||
vkDestroyImageView(device, depthImageView, nullptr);
|
||||
@@ -3015,8 +3071,6 @@ void Graphics::recreateSwapChain()
|
||||
createScreenshotCallbackBuffers();
|
||||
createColorResources();
|
||||
createDepthResources();
|
||||
createDefaultRenderPass();
|
||||
createDefaultFramebuffers();
|
||||
|
||||
transitionColorDepthLayouts = true;
|
||||
}
|
||||
|
||||
@@ -46,27 +46,43 @@ namespace graphics
|
||||
namespace vulkan
|
||||
{
|
||||
|
||||
struct RenderPassAttachment
|
||||
struct ColorAttachment
|
||||
{
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
bool discard = true;
|
||||
VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
bool operator==(const RenderPassAttachment &attachment) const
|
||||
bool operator==(const ColorAttachment &attachment) const
|
||||
{
|
||||
return format == attachment.format &&
|
||||
discard == attachment.discard &&
|
||||
loadOp == attachment.loadOp &&
|
||||
msaaSamples == attachment.msaaSamples;
|
||||
}
|
||||
};
|
||||
|
||||
struct DepthStencilAttachment
|
||||
{
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
bool operator==(const DepthStencilAttachment &attachment) const
|
||||
{
|
||||
return format == attachment.format &&
|
||||
depthLoadOp == attachment.depthLoadOp &&
|
||||
stencilLoadOp == attachment.stencilLoadOp &&
|
||||
msaaSamples == attachment.msaaSamples;
|
||||
}
|
||||
};
|
||||
|
||||
struct RenderPassConfiguration
|
||||
{
|
||||
std::vector<RenderPassAttachment> colorAttachments;
|
||||
std::vector<ColorAttachment> colorAttachments;
|
||||
|
||||
struct StaticRenderPassConfiguration
|
||||
{
|
||||
RenderPassAttachment depthAttachment;
|
||||
DepthStencilAttachment depthStencilAttachment;
|
||||
bool resolve = false;
|
||||
} staticData;
|
||||
|
||||
@@ -82,7 +98,7 @@ struct RenderPassConfigurationHasher
|
||||
size_t operator()(const RenderPassConfiguration &configuration) const
|
||||
{
|
||||
size_t hashes[] = {
|
||||
XXH32(configuration.colorAttachments.data(), configuration.colorAttachments.size() * sizeof(VkFormat), 0),
|
||||
XXH32(configuration.colorAttachments.data(), configuration.colorAttachments.size() * sizeof(ColorAttachment), 0),
|
||||
XXH32(&configuration.staticData, sizeof(configuration.staticData), 0),
|
||||
};
|
||||
return XXH32(hashes, sizeof(hashes), 0);
|
||||
@@ -130,7 +146,7 @@ struct OptionalInstanceExtensions
|
||||
bool physicalDeviceProperties2 = false;
|
||||
};
|
||||
|
||||
struct OptionalDeviceFeatures
|
||||
struct OptionalDeviceExtensions
|
||||
{
|
||||
// VK_EXT_extended_dynamic_state
|
||||
bool extendedDynamicState = false;
|
||||
@@ -141,9 +157,6 @@ struct OptionalDeviceFeatures
|
||||
// VK_KHR_dedicated_allocation
|
||||
bool dedicatedAllocation = false;
|
||||
|
||||
// VK_KHR_buffer_device_address
|
||||
bool bufferDeviceAddress = false;
|
||||
|
||||
// VK_EXT_memory_budget
|
||||
bool memoryBudget = false;
|
||||
|
||||
@@ -216,7 +229,7 @@ struct RenderpassState
|
||||
{
|
||||
bool active = false;
|
||||
VkRenderPassBeginInfo beginInfo{};
|
||||
bool useConfigurations = false;
|
||||
bool isWindow = false;
|
||||
RenderPassConfiguration renderPassConfiguration{};
|
||||
FramebufferConfiguration framebufferConfiguration{};
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
@@ -225,6 +238,12 @@ struct RenderpassState
|
||||
float width = 0.0f;
|
||||
float height = 0.0f;
|
||||
VkSampleCountFlagBits msaa = VK_SAMPLE_COUNT_1_BIT;
|
||||
std::vector<VkClearValue> clearColors;
|
||||
|
||||
bool windowClearRequested = false;
|
||||
OptionalColorD mainWindowClearColorValue;
|
||||
OptionalDouble mainWindowClearDepthValue;
|
||||
OptionalInt mainWindowClearStencilValue;
|
||||
};
|
||||
|
||||
struct ScreenshotReadbackBuffer
|
||||
@@ -293,9 +312,8 @@ public:
|
||||
graphics::Texture *getDefaultTexture() const;
|
||||
VkSampler getCachedSampler(const SamplerState &sampler);
|
||||
void setComputeShader(Shader *computeShader);
|
||||
std::set<Shader*> &getUsedShadersInFrame();
|
||||
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
|
||||
const OptionalDeviceFeatures &getEnabledOptionalDeviceExtensions() const;
|
||||
const OptionalDeviceExtensions &getEnabledOptionalDeviceExtensions() const;
|
||||
VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const;
|
||||
void setVsync(int vsync);
|
||||
int getVsync() const;
|
||||
@@ -317,6 +335,7 @@ private:
|
||||
int rateDeviceSuitability(VkPhysicalDevice device);
|
||||
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
|
||||
void createLogicalDevice();
|
||||
void createPipelineCache();
|
||||
void initVMA();
|
||||
void createSurface();
|
||||
bool checkDeviceExtensionSupport(VkPhysicalDevice device);
|
||||
@@ -328,12 +347,11 @@ private:
|
||||
void createSwapChain();
|
||||
void createImageViews();
|
||||
void createScreenshotCallbackBuffers();
|
||||
void createDefaultRenderPass();
|
||||
void createDefaultFramebuffers();
|
||||
VkFramebuffer createFramebuffer(FramebufferConfiguration &configuration);
|
||||
VkFramebuffer getFramebuffer(FramebufferConfiguration &configuration);
|
||||
void createDefaultShaders();
|
||||
VkRenderPass createRenderPass(RenderPassConfiguration &configuration);
|
||||
VkRenderPass getRenderPass(RenderPassConfiguration &configuration);
|
||||
VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration &configuration);
|
||||
void createColorResources();
|
||||
VkFormat findSupportedFormat(const std::vector<VkFormat> &candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
||||
@@ -375,7 +393,7 @@ private:
|
||||
int requestedMsaa = 0;
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
OptionalInstanceExtensions optionalInstanceExtensions;
|
||||
OptionalDeviceFeatures optionalDeviceFeatures;
|
||||
OptionalDeviceExtensions optionalDeviceExtensions;
|
||||
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
||||
VkQueue presentQueue = VK_NULL_HANDLE;
|
||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||
@@ -384,6 +402,7 @@ private:
|
||||
Matrix4 displayRotation;
|
||||
std::vector<VkImage> swapChainImages;
|
||||
VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED;
|
||||
VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D swapChainExtent = VkExtent2D();
|
||||
std::vector<VkImageView> swapChainImageViews;
|
||||
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
@@ -393,8 +412,7 @@ private:
|
||||
VkImage depthImage = VK_NULL_HANDLE;
|
||||
VkImageView depthImageView = VK_NULL_HANDLE;
|
||||
VmaAllocation depthImageAllocation = VK_NULL_HANDLE;
|
||||
VkRenderPass defaultRenderPass = VK_NULL_HANDLE;
|
||||
std::vector<VkFramebuffer> defaultFramebuffers;
|
||||
VkPipelineCache pipelineCache = VK_NULL_HANDLE;
|
||||
std::unordered_map<RenderPassConfiguration, VkRenderPass, RenderPassConfigurationHasher> renderPasses;
|
||||
std::unordered_map<FramebufferConfiguration, VkFramebuffer, FramebufferConfigurationHasher> framebuffers;
|
||||
std::unordered_map<GraphicsPipelineConfiguration, VkPipeline, GraphicsPipelineConfigurationHasher> graphicsPipelines;
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
@@ -144,6 +142,72 @@ static const TBuiltInResource defaultTBuiltInResource = {
|
||||
static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16;
|
||||
static const uint32_t DESCRIPTOR_POOL_SIZE = 1;
|
||||
|
||||
class BindingMapper
|
||||
{
|
||||
public:
|
||||
uint32_t operator()(spirv_cross::CompilerGLSL &comp, std::vector<uint32_t> &spirv, const std::string &name, const spirv_cross::ID &id)
|
||||
{
|
||||
auto it = bindingMappings.find(name);
|
||||
if (it == bindingMappings.end())
|
||||
{
|
||||
auto binding = comp.get_decoration(id, spv::DecorationBinding);
|
||||
|
||||
if (isFreeBinding(binding))
|
||||
{
|
||||
bindingMappings[name] = binding;
|
||||
return binding;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t freeBinding = getFreeBinding();
|
||||
|
||||
uint32_t binaryBindingOffset;
|
||||
if (!comp.get_binary_offset_for_decoration(id, spv::DecorationBinding, binaryBindingOffset))
|
||||
throw love::Exception("could not get binary offset for binding");
|
||||
|
||||
spirv[binaryBindingOffset] = freeBinding;
|
||||
|
||||
bindingMappings[name] = freeBinding;
|
||||
|
||||
return freeBinding;
|
||||
}
|
||||
}
|
||||
else
|
||||
return it->second;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
uint32_t getFreeBinding() {
|
||||
for (uint32_t i = 0;; i++)
|
||||
{
|
||||
bool free = true;
|
||||
for (const auto &entry : bindingMappings)
|
||||
{
|
||||
if (entry.second == i)
|
||||
{
|
||||
free = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (free)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
bool isFreeBinding(uint32_t binding) {
|
||||
for (const auto &entry : bindingMappings)
|
||||
{
|
||||
if (entry.second == binding)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::map<std::string, uint32_t> bindingMappings;
|
||||
|
||||
};
|
||||
|
||||
static VkShaderStageFlagBits getStageBit(ShaderStageType type)
|
||||
{
|
||||
switch (type)
|
||||
@@ -185,6 +249,8 @@ Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
|
||||
|
||||
bool Shader::loadVolatile()
|
||||
{
|
||||
device = vgfx->getDevice();
|
||||
|
||||
computePipeline = VK_NULL_HANDLE;
|
||||
|
||||
for (int i = 0; i < BUILTIN_MAX_ENUM; i++)
|
||||
@@ -200,6 +266,7 @@ bool Shader::loadVolatile()
|
||||
currentFrame = 0;
|
||||
currentUsedUniformStreamBuffersCount = 0;
|
||||
currentUsedDescriptorSetsCount = 0;
|
||||
newFrame();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -384,7 +451,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind
|
||||
for (const auto &u : uniformInfos)
|
||||
{
|
||||
if (updatedUniforms.find(u.second.location) == updatedUniforms.end())
|
||||
updateUniform(&u.second, u.second.count);
|
||||
updateUniform(&u.second, u.second.count, true);
|
||||
}
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr);
|
||||
@@ -406,13 +473,6 @@ Shader::~Shader()
|
||||
|
||||
void Shader::attach()
|
||||
{
|
||||
auto &usedShadersInFrame = vgfx->getUsedShadersInFrame();
|
||||
if (usedShadersInFrame.find(this) == usedShadersInFrame.end())
|
||||
{
|
||||
newFrame();
|
||||
usedShadersInFrame.insert(this);
|
||||
}
|
||||
|
||||
if (!isCompute)
|
||||
{
|
||||
if (Shader::current != this)
|
||||
@@ -676,11 +736,9 @@ void Shader::compileShaders()
|
||||
using namespace glslang;
|
||||
using namespace spirv_cross;
|
||||
|
||||
std::vector<TShader*> glslangShaders;
|
||||
std::vector<std::unique_ptr<TShader>> glslangShaders;
|
||||
|
||||
auto program = new TProgram();
|
||||
|
||||
device = vgfx->getDevice();
|
||||
auto program = std::make_unique<TProgram>();
|
||||
|
||||
const auto &enabledExtensions = vgfx->getEnabledOptionalDeviceExtensions();
|
||||
|
||||
@@ -695,7 +753,7 @@ void Shader::compileShaders()
|
||||
isCompute = true;
|
||||
|
||||
auto glslangShaderStage = getGlslShaderType(stage);
|
||||
auto tshader = new TShader(glslangShaderStage);
|
||||
auto tshader = std::make_unique<TShader>(glslangShaderStage);
|
||||
|
||||
tshader->setEnvInput(EShSourceGlsl, glslangShaderStage, EShClientVulkan, 450);
|
||||
tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2);
|
||||
@@ -721,14 +779,18 @@ void Shader::compileShaders()
|
||||
|
||||
if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings))
|
||||
{
|
||||
const char *msg1 = tshader->getInfoLog();
|
||||
const char *msg2 = tshader->getInfoDebugLog();
|
||||
const char *stageName = "unknown";
|
||||
ShaderStage::getConstant(stage, stageName);
|
||||
|
||||
throw love::Exception("error while parsing shader");
|
||||
std::string err = "Error parsing " + std::string(stageName) + " shader:\n\n"
|
||||
+ std::string(tshader->getInfoLog()) + "\n"
|
||||
+ std::string(tshader->getInfoDebugLog());
|
||||
|
||||
throw love::Exception("%s", err.c_str());
|
||||
}
|
||||
|
||||
program->addShader(tshader);
|
||||
glslangShaders.push_back(tshader);
|
||||
program->addShader(tshader.get());
|
||||
glslangShaders.push_back(std::move(tshader));
|
||||
}
|
||||
|
||||
if (!program->link(EShMsgDefault))
|
||||
@@ -739,14 +801,16 @@ void Shader::compileShaders()
|
||||
|
||||
uniformInfos.clear();
|
||||
|
||||
BindingMapper bindingMapper;
|
||||
|
||||
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
|
||||
{
|
||||
auto shaderStage = (ShaderStageType)i;
|
||||
auto glslangStage = getGlslShaderType(shaderStage);
|
||||
auto intermediate = program->getIntermediate(glslangStage);
|
||||
if (intermediate == nullptr) {
|
||||
|
||||
if (intermediate == nullptr)
|
||||
continue;
|
||||
}
|
||||
|
||||
spv::SpvBuildLogger logger;
|
||||
glslang::SpvOptions opt;
|
||||
@@ -755,31 +819,6 @@ void Shader::compileShaders()
|
||||
std::vector<uint32_t> spirv;
|
||||
GlslangToSpv(*intermediate, spirv, &logger, &opt);
|
||||
|
||||
std::string msgs = logger.getAllMessages();
|
||||
|
||||
VkShaderModuleCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = spirv.size() * sizeof(uint32_t);
|
||||
createInfo.pCode = spirv.data();
|
||||
|
||||
auto device = vgfx->getDevice();
|
||||
|
||||
VkShaderModule shaderModule;
|
||||
|
||||
if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
|
||||
throw love::Exception("failed to create shader module");
|
||||
}
|
||||
|
||||
shaderModules.push_back(shaderModule);
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStageInfo{};
|
||||
shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shaderStageInfo.stage = getStageBit((ShaderStageType)i);
|
||||
shaderStageInfo.module = shaderModule;
|
||||
shaderStageInfo.pName = "main";
|
||||
|
||||
shaderStages.push_back(shaderStageInfo);
|
||||
|
||||
spirv_cross::CompilerGLSL comp(spirv);
|
||||
|
||||
// we only care about variables that are actually getting used.
|
||||
@@ -796,7 +835,7 @@ void Shader::compileShaders()
|
||||
auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
|
||||
localUniformStagingData.resize(defaultUniformBlockSize);
|
||||
localUniformData.resize(defaultUniformBlockSize);
|
||||
localUniformLocation = comp.get_decoration(resource.id, spv::DecorationBinding);
|
||||
localUniformLocation = bindingMapper(comp, spirv, resource.name, resource.id);
|
||||
|
||||
memset(localUniformStagingData.data(), 0, defaultUniformBlockSize);
|
||||
memset(localUniformData.data(), 0, defaultUniformBlockSize);
|
||||
@@ -817,7 +856,7 @@ void Shader::compileShaders()
|
||||
const SPIRType &imagetype = comp.get_type(basetype.image.type);
|
||||
|
||||
graphics::Shader::UniformInfo info;
|
||||
info.location = comp.get_decoration(r.id, spv::DecorationBinding);
|
||||
info.location = bindingMapper(comp, spirv, r.name, r.id);
|
||||
info.baseType = UNIFORM_SAMPLER;
|
||||
info.name = r.name;
|
||||
info.count = type.array.empty() ? 1 : type.array[0];
|
||||
@@ -898,7 +937,7 @@ void Shader::compileShaders()
|
||||
if (!fillUniformReflectionData(u))
|
||||
continue;
|
||||
|
||||
u.location = comp.get_decoration(r.id, spv::DecorationBinding);
|
||||
u.location = bindingMapper(comp, spirv, r.name, r.id);
|
||||
u.buffers = new love::graphics::Buffer *[u.count];
|
||||
|
||||
for (int i = 0; i < u.count; i++)
|
||||
@@ -921,13 +960,11 @@ void Shader::compileShaders()
|
||||
continue;
|
||||
|
||||
u.textures = new love::graphics::Texture *[u.count];
|
||||
u.location = comp.get_decoration(r.id, spv::DecorationBinding);
|
||||
u.location = bindingMapper(comp, spirv, r.name, r.id);
|
||||
|
||||
for (int i = 0; i < u.count; i++)
|
||||
u.textures[i] = nullptr;
|
||||
|
||||
// some stuff missing ?
|
||||
|
||||
uniformInfos[u.name] = u;
|
||||
}
|
||||
|
||||
@@ -940,11 +977,27 @@ void Shader::compileShaders()
|
||||
attributes[name] = attributeLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete program;
|
||||
for (auto shader : glslangShaders)
|
||||
delete shader;
|
||||
VkShaderModuleCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = spirv.size() * sizeof(uint32_t);
|
||||
createInfo.pCode = spirv.data();
|
||||
|
||||
VkShaderModule shaderModule;
|
||||
|
||||
if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS)
|
||||
throw love::Exception("failed to create shader module");
|
||||
|
||||
shaderModules.push_back(shaderModule);
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStageInfo{};
|
||||
shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shaderStageInfo.stage = getStageBit((ShaderStageType)i);
|
||||
shaderStageInfo.module = shaderModule;
|
||||
shaderStageInfo.pName = "main";
|
||||
|
||||
shaderStages.push_back(shaderStageInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::createDescriptorSetLayout()
|
||||
|
||||
Reference in New Issue
Block a user