mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
Merge pull request #1958 from nikeinikei/12.0-development
vk: maintenance
This commit is contained in:
@@ -514,7 +514,7 @@ void Graphics::present(void *screenshotCallbackdata)
|
||||
|
||||
void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight)
|
||||
{
|
||||
if (swapChain != VK_NULL_HANDLE && (pixelWidth != this->pixelWidth || pixelHeight != this->pixelHeight || width != this->width || height != this->height))
|
||||
if (swapChain != VK_NULL_HANDLE && (pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight || width != this->width || height != this->height))
|
||||
requestSwapchainRecreation();
|
||||
|
||||
this->width = width;
|
||||
@@ -559,8 +559,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
|
||||
beginFrame();
|
||||
|
||||
uint8 whiteColor[] = { 255, 255, 255, 255 };
|
||||
|
||||
if (batchedDrawState.vb[0] == nullptr)
|
||||
{
|
||||
// Initial sizes that should be good enough for most cases. It will
|
||||
@@ -570,9 +568,19 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
batchedDrawState.indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||
}
|
||||
|
||||
// sometimes the VertexTexCoord is not set, so we manually adjust it to (0, 0)
|
||||
if (defaultConstantTexCoord == nullptr)
|
||||
{
|
||||
float zeroTexCoord[2] = { 0.0f, 0.0f };
|
||||
Buffer::DataDeclaration format("ConstantTexCoord", DATAFORMAT_FLOAT_VEC2);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC);
|
||||
defaultConstantTexCoord = newBuffer(settings, { format }, zeroTexCoord, sizeof(zeroTexCoord), 1);
|
||||
}
|
||||
|
||||
// sometimes the VertexColor is not set, so we manually adjust it to white color
|
||||
if (defaultConstantColor == nullptr)
|
||||
{
|
||||
uint8 whiteColor[] = { 255, 255, 255, 255 };
|
||||
Buffer::DataDeclaration format("ConstantColor", DATAFORMAT_UNORM8_VEC4);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC);
|
||||
defaultConstantColor = newBuffer(settings, { format }, whiteColor, sizeof(whiteColor), 1);
|
||||
@@ -1173,7 +1181,6 @@ void Graphics::beginFrame()
|
||||
|
||||
if (frameCounter >= USAGES_POLL_INTERVAL)
|
||||
{
|
||||
vkDeviceWaitIdle(device);
|
||||
cleanupUnusedObjects();
|
||||
frameCounter = 0;
|
||||
}
|
||||
@@ -1263,11 +1270,6 @@ const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const
|
||||
return minUniformBufferOffsetAlignment;
|
||||
}
|
||||
|
||||
graphics::Texture *Graphics::getDefaultTexture() const
|
||||
{
|
||||
return defaultTexture;
|
||||
}
|
||||
|
||||
VkCommandBuffer Graphics::getCommandBufferForDataTransfer()
|
||||
{
|
||||
if (renderPassState.active)
|
||||
@@ -1653,10 +1655,11 @@ void Graphics::createLogicalDevice()
|
||||
|
||||
VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures{};
|
||||
extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;
|
||||
extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceExtensions.extendedDynamicState);
|
||||
extendedDynamicStateFeatures.extendedDynamicState = VK_TRUE;
|
||||
extendedDynamicStateFeatures.pNext = nullptr;
|
||||
|
||||
createInfo.pNext = &extendedDynamicStateFeatures;
|
||||
if (optionalDeviceExtensions.extendedDynamicState)
|
||||
createInfo.pNext = &extendedDynamicStateFeatures;
|
||||
|
||||
if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS)
|
||||
throw love::Exception("failed to create logical device");
|
||||
@@ -1850,20 +1853,34 @@ void Graphics::createSwapChain()
|
||||
|
||||
VkSurfaceFormatKHR Graphics::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats)
|
||||
{
|
||||
std::vector<VkFormat> formatOrder;
|
||||
|
||||
// TODO: turn off GammaCorrect if a sRGB format can't be found?
|
||||
// TODO: does every platform have these formats?
|
||||
if (isGammaCorrect())
|
||||
{
|
||||
for (const auto &availableFormat : availableFormats)
|
||||
// fixme: what if this format and colorspace is not available?
|
||||
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return availableFormat;
|
||||
formatOrder = {
|
||||
VK_FORMAT_B8G8R8A8_SRGB,
|
||||
VK_FORMAT_R8G8B8A8_SRGB,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
formatOrder = {
|
||||
VK_FORMAT_B8G8R8A8_UNORM,
|
||||
VK_FORMAT_R8G8B8A8_SNORM,
|
||||
};
|
||||
}
|
||||
|
||||
for (const auto &availableFormat : availableFormats)
|
||||
// fixme: what if this format and colorspace is not available?
|
||||
if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return availableFormat;
|
||||
|
||||
for (const auto format : formatOrder)
|
||||
{
|
||||
for (const auto &availableFormat : availableFormats)
|
||||
{
|
||||
if (availableFormat.format == format && availableFormat.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR)
|
||||
return availableFormat;
|
||||
}
|
||||
}
|
||||
|
||||
return availableFormats[0];
|
||||
}
|
||||
|
||||
@@ -2208,11 +2225,6 @@ VkRenderPass Graphics::getRenderPass(RenderPassConfiguration &configuration)
|
||||
return renderPass;
|
||||
}
|
||||
|
||||
bool Graphics::usesConstantVertexColor(const VertexAttributes &vertexAttributes)
|
||||
{
|
||||
return !!(vertexAttributes.enableBits & (1u << ATTRIB_COLOR));
|
||||
}
|
||||
|
||||
void Graphics::createVulkanVertexFormat(
|
||||
VertexAttributes vertexAttributes,
|
||||
std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
|
||||
@@ -2224,6 +2236,7 @@ void Graphics::createVulkanVertexFormat(
|
||||
auto allBits = enableBits;
|
||||
|
||||
bool usesColor = false;
|
||||
bool usesTexCoord = false;
|
||||
|
||||
uint8_t highestBufferBinding = 0;
|
||||
|
||||
@@ -2233,6 +2246,8 @@ void Graphics::createVulkanVertexFormat(
|
||||
uint32 bit = 1u << i;
|
||||
if (enableBits & bit)
|
||||
{
|
||||
if (i == ATTRIB_TEXCOORD)
|
||||
usesTexCoord = true;
|
||||
if (i == ATTRIB_COLOR)
|
||||
usesColor = true;
|
||||
|
||||
@@ -2267,11 +2282,31 @@ void Graphics::createVulkanVertexFormat(
|
||||
allBits >>= 1;
|
||||
}
|
||||
|
||||
if (!usesTexCoord)
|
||||
{
|
||||
// FIXME: is there a case where gaps happen between buffer bindings?
|
||||
// then this doesn't work. We might need to enable null buffers again.
|
||||
const auto constantTexCoordBufferBinding = ++highestBufferBinding;
|
||||
|
||||
VkVertexInputBindingDescription bindingDescription{};
|
||||
bindingDescription.binding = constantTexCoordBufferBinding;
|
||||
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
bindingDescription.stride = 0; // no stride, will always read the same coord multiple times.
|
||||
bindingDescriptions.push_back(bindingDescription);
|
||||
|
||||
VkVertexInputAttributeDescription attributeDescription{};
|
||||
attributeDescription.binding = constantTexCoordBufferBinding;
|
||||
attributeDescription.location = ATTRIB_TEXCOORD;
|
||||
attributeDescription.offset = 0;
|
||||
attributeDescription.format = VK_FORMAT_R32G32_SFLOAT;
|
||||
attributeDescriptions.push_back(attributeDescription);
|
||||
}
|
||||
|
||||
if (!usesColor)
|
||||
{
|
||||
// FIXME: is there a case where gaps happen between buffer bindings?
|
||||
// then this doesn't work. We might need to enable null buffers again.
|
||||
const auto constantColorBufferBinding = highestBufferBinding + 1;
|
||||
const auto constantColorBufferBinding = ++highestBufferBinding;
|
||||
|
||||
VkVertexInputBindingDescription bindingDescription{};
|
||||
bindingDescription.binding = constantColorBufferBinding;
|
||||
@@ -2331,7 +2366,13 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
|
||||
}
|
||||
}
|
||||
|
||||
if (!usesConstantVertexColor(attributes))
|
||||
if (!(attributes.enableBits & (1u << ATTRIB_TEXCOORD)))
|
||||
{
|
||||
bufferVector.push_back((VkBuffer)defaultConstantTexCoord->getHandle());
|
||||
offsets.push_back((VkDeviceSize)0);
|
||||
}
|
||||
|
||||
if (!(attributes.enableBits & (1u << ATTRIB_COLOR)))
|
||||
{
|
||||
bufferVector.push_back((VkBuffer)defaultConstantColor->getHandle());
|
||||
offsets.push_back((VkDeviceSize)0);
|
||||
@@ -2402,8 +2443,6 @@ void Graphics::setDefaultRenderPass()
|
||||
|
||||
void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture)
|
||||
{
|
||||
auto currentCommandBuffer = commandBuffers.at(currentFrame);
|
||||
|
||||
// fixme: hasSRGBtexture
|
||||
RenderPassConfiguration renderPassConfiguration{};
|
||||
for (const auto &color : rts.colors)
|
||||
|
||||
@@ -262,13 +262,12 @@ public:
|
||||
Graphics();
|
||||
~Graphics();
|
||||
|
||||
const char *getName() const override;
|
||||
const VkDevice getDevice() const;
|
||||
const VmaAllocator getVmaAllocator() const;
|
||||
|
||||
// implementation for virtual functions
|
||||
const char *getName() const override;
|
||||
love::graphics::Texture *newTexture(const love::graphics::Texture::Settings &settings, const love::graphics::Texture::Slices *data) override;
|
||||
love::graphics::Buffer *newBuffer(const love::graphics::Buffer::Settings &settings, const std::vector<love::graphics::Buffer::DataDeclaration>& format, const void *data, size_t size, size_t arraylength) override;
|
||||
graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override;
|
||||
graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override;
|
||||
void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
|
||||
void clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) override;
|
||||
Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override;
|
||||
@@ -299,17 +298,15 @@ public:
|
||||
void draw(const DrawIndexedCommand &cmd) override;
|
||||
void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture) override;
|
||||
|
||||
graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override;
|
||||
graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override;
|
||||
|
||||
// internal functions.
|
||||
|
||||
const VkDevice getDevice() const;
|
||||
const VmaAllocator getVmaAllocator() const;
|
||||
VkCommandBuffer getCommandBufferForDataTransfer();
|
||||
void queueCleanUp(std::function<void()> cleanUp);
|
||||
void addReadbackCallback(std::function<void()> callback);
|
||||
void submitGpuCommands(bool present, void *screenshotCallbackData = nullptr);
|
||||
const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
|
||||
graphics::Texture *getDefaultTexture() const;
|
||||
VkSampler getCachedSampler(const SamplerState &sampler);
|
||||
void setComputeShader(Shader *computeShader);
|
||||
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
|
||||
@@ -369,7 +366,6 @@ private:
|
||||
void startRecordingGraphicsCommands();
|
||||
void endRecordingGraphicsCommands();
|
||||
void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration);
|
||||
bool usesConstantVertexColor(const VertexAttributes &attribs);
|
||||
void createVulkanVertexFormat(
|
||||
VertexAttributes vertexAttributes,
|
||||
std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
|
||||
@@ -438,6 +434,7 @@ private:
|
||||
VmaAllocator vmaAllocator = VK_NULL_HANDLE;
|
||||
StrongRef<love::graphics::Texture> defaultTexture;
|
||||
StrongRef<love::graphics::Buffer> defaultConstantColor;
|
||||
StrongRef<love::graphics::Buffer> defaultConstantTexCoord;
|
||||
// functions that need to be called to cleanup objects that were needed for rendering a frame.
|
||||
// We need a vector for each frame in flight.
|
||||
std::vector<std::vector<std::function<void()>>> cleanUpFunctions;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#include "graphics/vertex.h"
|
||||
#include "Shader.h"
|
||||
#include "Graphics.h"
|
||||
|
||||
@@ -140,7 +141,7 @@ static const TBuiltInResource defaultTBuiltInResource = {
|
||||
};
|
||||
|
||||
static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16;
|
||||
static const uint32_t DESCRIPTOR_POOL_SIZE = 1;
|
||||
static const uint32_t DESCRIPTOR_POOL_SIZE = 1000;
|
||||
|
||||
class BindingMapper
|
||||
{
|
||||
@@ -178,24 +179,17 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
uint32_t getFreeBinding() {
|
||||
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)
|
||||
if (isFreeBinding(i))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
bool isFreeBinding(uint32_t binding) {
|
||||
bool isFreeBinding(uint32_t binding)
|
||||
{
|
||||
for (const auto &entry : bindingMappings)
|
||||
{
|
||||
if (entry.second == binding)
|
||||
@@ -218,8 +212,8 @@ static VkShaderStageFlagBits getStageBit(ShaderStageType type)
|
||||
return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
case SHADERSTAGE_COMPUTE:
|
||||
return VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
default:
|
||||
throw love::Exception("invalid type");
|
||||
default:
|
||||
throw love::Exception("invalid type");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +232,15 @@ static EShLanguage getGlslShaderType(ShaderStageType stage)
|
||||
}
|
||||
}
|
||||
|
||||
static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info)
|
||||
{
|
||||
return info->baseType == graphics::Shader::UNIFORM_BOOL ||
|
||||
info->baseType == graphics::Shader::UNIFORM_FLOAT ||
|
||||
info->baseType == graphics::Shader::UNIFORM_INT ||
|
||||
info->baseType == graphics::Shader::UNIFORM_MATRIX ||
|
||||
info->baseType == graphics::Shader::UNIFORM_UINT;
|
||||
}
|
||||
|
||||
Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
|
||||
: graphics::Shader(stages)
|
||||
{
|
||||
@@ -262,10 +265,9 @@ bool Shader::loadVolatile()
|
||||
createPipelineLayout();
|
||||
createDescriptorPoolSizes();
|
||||
createStreamBuffers();
|
||||
descriptorSetsVector.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
descriptorPools.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
currentFrame = 0;
|
||||
currentUsedUniformStreamBuffersCount = 0;
|
||||
currentUsedDescriptorSetsCount = 0;
|
||||
newFrame();
|
||||
|
||||
return true;
|
||||
@@ -302,8 +304,11 @@ void Shader::unloadVolatile()
|
||||
}
|
||||
|
||||
vgfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){
|
||||
for (const auto pool : descriptorPools)
|
||||
vkDestroyDescriptorPool(device, pool, nullptr);
|
||||
for (const auto &pools : descriptorPools)
|
||||
{
|
||||
for (const auto pool : pools)
|
||||
vkDestroyDescriptorPool(device, pool, nullptr);
|
||||
}
|
||||
for (const auto shaderModule : shaderModules)
|
||||
vkDestroyShaderModule(device, shaderModule, nullptr);
|
||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||
@@ -312,9 +317,6 @@ void Shader::unloadVolatile()
|
||||
vkDestroyPipeline(device, computePipeline, nullptr);
|
||||
});
|
||||
|
||||
while (!freeDescriptorSets.empty())
|
||||
freeDescriptorSets.pop();
|
||||
|
||||
for (const auto streamBuffer : streamBuffers)
|
||||
streamBuffer->release();
|
||||
|
||||
@@ -322,7 +324,6 @@ void Shader::unloadVolatile()
|
||||
shaderStages.clear();
|
||||
streamBuffers.clear();
|
||||
descriptorPools.clear();
|
||||
descriptorSetsVector.clear();
|
||||
}
|
||||
|
||||
const std::vector<VkPipelineShaderStageCreateInfo> &Shader::getShaderStages() const
|
||||
@@ -344,9 +345,8 @@ void Shader::newFrame()
|
||||
{
|
||||
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
|
||||
updatedUniforms.clear();
|
||||
currentUsedUniformStreamBuffersCount = 0;
|
||||
currentUsedDescriptorSetsCount = 0;
|
||||
currentDescriptorPool = 0;
|
||||
|
||||
if (streamBuffers.size() > 1)
|
||||
{
|
||||
@@ -362,14 +362,25 @@ void Shader::newFrame()
|
||||
else
|
||||
streamBuffers.at(0)->nextFrame();
|
||||
|
||||
if (descriptorSetsVector.at(currentFrame).size() == 0)
|
||||
descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
|
||||
|
||||
currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(0);
|
||||
for (VkDescriptorPool pool : descriptorPools[currentFrame])
|
||||
vkResetDescriptorPool(device, pool, 0);
|
||||
}
|
||||
|
||||
void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint)
|
||||
{
|
||||
VkDescriptorSet currentDescriptorSet = allocateDescriptorSet();
|
||||
|
||||
std::vector<VkDescriptorBufferInfo> bufferInfos;
|
||||
bufferInfos.reserve(numBuffers);
|
||||
|
||||
std::vector<VkDescriptorImageInfo> imageInfos;
|
||||
imageInfos.reserve(numTextures);
|
||||
|
||||
std::vector<VkBufferView> bufferViews;
|
||||
bufferViews.reserve(numBufferViews);
|
||||
|
||||
std::vector<VkWriteDescriptorSet> descriptorWrites;
|
||||
|
||||
if (!localUniformData.empty())
|
||||
{
|
||||
auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
|
||||
@@ -398,6 +409,8 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind
|
||||
bufferInfo.offset = offset;
|
||||
bufferInfo.range = localUniformData.size();
|
||||
|
||||
bufferInfos.push_back(bufferInfo);
|
||||
|
||||
VkWriteDescriptorSet uniformWrite{};
|
||||
uniformWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
uniformWrite.dstSet = currentDescriptorSet;
|
||||
@@ -405,65 +418,109 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBind
|
||||
uniformWrite.dstArrayElement = 0;
|
||||
uniformWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
uniformWrite.descriptorCount = 1;
|
||||
uniformWrite.pBufferInfo = &bufferInfo;
|
||||
uniformWrite.pBufferInfo = &bufferInfos[bufferInfos.size() - 1];
|
||||
|
||||
vkUpdateDescriptorSets(device, 1, &uniformWrite, 0, nullptr);
|
||||
descriptorWrites.push_back(uniformWrite);
|
||||
|
||||
currentUsedUniformStreamBuffersCount++;
|
||||
|
||||
updatedUniforms.insert(localUniformLocation);
|
||||
}
|
||||
|
||||
static const std::vector<BuiltinUniform> builtinUniformTextures = {
|
||||
BUILTIN_TEXTURE_MAIN,
|
||||
BUILTIN_TEXTURE_VIDEO_Y,
|
||||
BUILTIN_TEXTURE_VIDEO_CB,
|
||||
BUILTIN_TEXTURE_VIDEO_CR,
|
||||
};
|
||||
|
||||
for (const auto &builtin : builtinUniformTextures)
|
||||
{
|
||||
if (builtinUniformInfo[builtin] != nullptr)
|
||||
{
|
||||
auto texture = dynamic_cast<Texture*>(builtinUniformInfo[builtin]->textures[0]);
|
||||
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
imageInfo.imageLayout = texture->getImageLayout();
|
||||
imageInfo.imageView = (VkImageView)texture->getRenderTargetHandle();
|
||||
imageInfo.sampler = (VkSampler)texture->getSamplerHandle();
|
||||
|
||||
auto location = builtinUniformInfo[builtin]->location;
|
||||
|
||||
VkWriteDescriptorSet textureWrite{};
|
||||
textureWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
textureWrite.dstSet = currentDescriptorSet;
|
||||
textureWrite.dstBinding = location;
|
||||
textureWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
textureWrite.descriptorCount = 1;
|
||||
textureWrite.pImageInfo = &imageInfo;
|
||||
|
||||
vkUpdateDescriptorSets(device, 1, &textureWrite, 0, nullptr);
|
||||
|
||||
updatedUniforms.insert(location);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &u : uniformInfos)
|
||||
{
|
||||
if (updatedUniforms.find(u.second.location) == updatedUniforms.end())
|
||||
updateUniform(&u.second, u.second.count, true);
|
||||
auto &info = u.second;
|
||||
|
||||
if (usesLocalUniformData(&info))
|
||||
continue;
|
||||
|
||||
if (info.baseType == UNIFORM_SAMPLER || info.baseType == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
bool isSampler = info.baseType == UNIFORM_SAMPLER;
|
||||
|
||||
for (int i = 0; i < info.count; i++)
|
||||
{
|
||||
auto vkTexture = dynamic_cast<Texture*>(info.textures[i]);
|
||||
|
||||
if (vkTexture == nullptr)
|
||||
throw love::Exception("uniform variable %s is not set.", info.name.c_str());
|
||||
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
|
||||
imageInfo.imageLayout = vkTexture->getImageLayout();
|
||||
imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle();
|
||||
if (isSampler)
|
||||
imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle();
|
||||
|
||||
imageInfos.push_back(imageInfo);
|
||||
}
|
||||
|
||||
VkWriteDescriptorSet write{};
|
||||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write.dstSet = currentDescriptorSet;
|
||||
write.dstBinding = info.location;
|
||||
write.dstArrayElement = 0;
|
||||
if (isSampler)
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
else
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
write.descriptorCount = static_cast<uint32_t>(info.count);
|
||||
write.pImageInfo = &imageInfos[imageInfos.size() - info.count];
|
||||
|
||||
descriptorWrites.push_back(write);
|
||||
}
|
||||
if (info.baseType == UNIFORM_STORAGEBUFFER)
|
||||
{
|
||||
VkWriteDescriptorSet write{};
|
||||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write.dstSet = currentDescriptorSet;
|
||||
write.dstBinding = info.location;
|
||||
write.dstArrayElement = 0;
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
write.descriptorCount = info.count;
|
||||
|
||||
for (int i = 0; i < info.count; i++)
|
||||
{
|
||||
if (info.buffers[i] == nullptr)
|
||||
throw love::Exception("uniform variable %s is not set.", info.name.c_str());
|
||||
|
||||
VkDescriptorBufferInfo bufferInfo{};
|
||||
bufferInfo.buffer = (VkBuffer)info.buffers[i]->getHandle();;
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = info.buffers[i]->getSize();
|
||||
|
||||
bufferInfos.push_back(bufferInfo);
|
||||
}
|
||||
|
||||
write.pBufferInfo = &bufferInfos[bufferInfos.size() - info.count];
|
||||
|
||||
descriptorWrites.push_back(write);
|
||||
}
|
||||
if (info.baseType == UNIFORM_TEXELBUFFER)
|
||||
{
|
||||
VkWriteDescriptorSet write{};
|
||||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write.dstSet = currentDescriptorSet;
|
||||
write.dstBinding = info.location;
|
||||
write.dstArrayElement = 0;
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
|
||||
write.descriptorCount = info.count;
|
||||
|
||||
for (int i = 0; i < info.count; i++)
|
||||
{
|
||||
if (info.buffers[i] == nullptr)
|
||||
throw love::Exception("uniform variable %s is not set.", info.name.c_str());
|
||||
|
||||
bufferViews.push_back((VkBufferView)info.buffers[i]->getTexelBufferHandle());
|
||||
}
|
||||
|
||||
write.pTexelBufferView = &bufferViews[bufferViews.size() - info.count];
|
||||
|
||||
descriptorWrites.push_back(write);
|
||||
}
|
||||
}
|
||||
|
||||
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr);
|
||||
|
||||
currentUsedDescriptorSetsCount++;
|
||||
|
||||
if (currentUsedDescriptorSetsCount >= static_cast<uint32_t>(descriptorSetsVector.at(currentFrame).size()))
|
||||
descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
|
||||
|
||||
currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
|
||||
|
||||
updatedUniforms.clear();
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
@@ -502,119 +559,13 @@ const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const
|
||||
return builtinUniformInfo[builtin];
|
||||
}
|
||||
|
||||
static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info)
|
||||
{
|
||||
return info->baseType == graphics::Shader::UNIFORM_BOOL ||
|
||||
info->baseType == graphics::Shader::UNIFORM_FLOAT ||
|
||||
info->baseType == graphics::Shader::UNIFORM_INT ||
|
||||
info->baseType == graphics::Shader::UNIFORM_MATRIX ||
|
||||
info->baseType == graphics::Shader::UNIFORM_UINT;
|
||||
}
|
||||
|
||||
void Shader::updateUniform(const UniformInfo *info, int count)
|
||||
{
|
||||
updateUniform(info, count, false);
|
||||
}
|
||||
|
||||
void Shader::updateUniform(const UniformInfo* info, int count, bool internal)
|
||||
{
|
||||
if (!internal && current == this)
|
||||
if (current == this)
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
|
||||
if (usesLocalUniformData(info))
|
||||
memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size());
|
||||
if (info->baseType == UNIFORM_SAMPLER || info->baseType == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
bool isSampler = info->baseType == UNIFORM_SAMPLER;
|
||||
|
||||
std::vector<VkDescriptorImageInfo> imageInfos;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
auto vkTexture = dynamic_cast<Texture*>(info->textures[i]);
|
||||
|
||||
if (vkTexture == nullptr)
|
||||
throw love::Exception("uniform variable %s is not set.", info->name.c_str());
|
||||
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
|
||||
imageInfo.imageLayout = vkTexture->getImageLayout();
|
||||
imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle();
|
||||
if (isSampler)
|
||||
imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle();
|
||||
|
||||
imageInfos.push_back(imageInfo);
|
||||
}
|
||||
|
||||
VkWriteDescriptorSet write{};
|
||||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write.dstSet = currentDescriptorSet;
|
||||
write.dstBinding = info->location;
|
||||
write.dstArrayElement = 0;
|
||||
if (isSampler)
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
else
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
write.descriptorCount = static_cast<uint32_t>(count);
|
||||
write.pImageInfo = imageInfos.data();
|
||||
|
||||
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
|
||||
}
|
||||
if (info->baseType == UNIFORM_STORAGEBUFFER)
|
||||
{
|
||||
VkWriteDescriptorSet write{};
|
||||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write.dstSet = currentDescriptorSet;
|
||||
write.dstBinding = info->location;
|
||||
write.dstArrayElement = 0;
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
write.descriptorCount = info->count;
|
||||
|
||||
std::vector<VkDescriptorBufferInfo> bufferInfos;
|
||||
|
||||
for (int i = 0; i < info->count; i++)
|
||||
{
|
||||
if (info->buffers[i] == nullptr)
|
||||
throw love::Exception("uniform variable %s is not set.", info->name.c_str());
|
||||
|
||||
VkDescriptorBufferInfo bufferInfo{};
|
||||
bufferInfo.buffer = (VkBuffer)info->buffers[i]->getHandle();;
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = info->buffers[i]->getSize();
|
||||
|
||||
bufferInfos.push_back(bufferInfo);
|
||||
}
|
||||
|
||||
write.pBufferInfo = bufferInfos.data();
|
||||
|
||||
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
|
||||
}
|
||||
if (info->baseType == UNIFORM_TEXELBUFFER)
|
||||
{
|
||||
VkWriteDescriptorSet write{};
|
||||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write.dstSet = currentDescriptorSet;
|
||||
write.dstBinding = info->location;
|
||||
write.dstArrayElement = 0;
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
|
||||
write.descriptorCount = info->count;
|
||||
|
||||
std::vector<VkBufferView> bufferViews;
|
||||
|
||||
for (int i = 0; i < info->count; i++)
|
||||
{
|
||||
if (info->buffers[i] == nullptr)
|
||||
throw love::Exception("uniform variable %s is not set.", info->name.c_str());
|
||||
|
||||
bufferViews.push_back((VkBufferView)info->buffers[i]->getTexelBufferHandle());
|
||||
}
|
||||
|
||||
write.pTexelBufferView = bufferViews.data();
|
||||
|
||||
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
|
||||
}
|
||||
|
||||
updatedUniforms.insert(info->location);
|
||||
}
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count)
|
||||
@@ -627,8 +578,6 @@ void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures,
|
||||
if (oldTexture)
|
||||
oldTexture->release();
|
||||
}
|
||||
|
||||
updateUniform(info, count);
|
||||
}
|
||||
|
||||
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
|
||||
@@ -641,17 +590,13 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
|
||||
if (oldBuffer)
|
||||
oldBuffer->release();
|
||||
}
|
||||
|
||||
updateUniform(info, count);
|
||||
}
|
||||
|
||||
void Shader::calculateUniformBufferSizeAligned()
|
||||
{
|
||||
auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment();
|
||||
size_t size = localUniformStagingData.size();
|
||||
auto factor = static_cast<VkDeviceSize>(std::ceil(
|
||||
static_cast<float>(size) / static_cast<float>(minAlignment)
|
||||
));
|
||||
auto factor = static_cast<VkDeviceSize>(std::ceil(static_cast<float>(size) / static_cast<float>(minAlignment)));
|
||||
uniformBufferSizeAligned = factor * minAlignment;
|
||||
}
|
||||
|
||||
@@ -830,9 +775,9 @@ void Shader::compileShaders()
|
||||
{
|
||||
if (resource.name == "gl_DefaultUniformBlock")
|
||||
{
|
||||
const auto& type = comp.get_type(resource.base_type_id);
|
||||
size_t uniformBufferObjectSize = comp.get_declared_struct_size(type);
|
||||
auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
|
||||
const auto &type = comp.get_type(resource.base_type_id);
|
||||
size_t defaultUniformBlockSize = comp.get_declared_struct_size(type);
|
||||
|
||||
localUniformStagingData.resize(defaultUniformBlockSize);
|
||||
localUniformData.resize(defaultUniformBlockSize);
|
||||
localUniformLocation = bindingMapper(comp, spirv, resource.name, resource.id);
|
||||
@@ -910,11 +855,9 @@ void Shader::compileShaders()
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tex = vgfx->getDefaultTexture();
|
||||
for (int i = 0; i < info.count; i++)
|
||||
{
|
||||
info.textures[i] = tex;
|
||||
tex->retain();
|
||||
info.textures[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -970,11 +913,25 @@ void Shader::compileShaders()
|
||||
|
||||
if (shaderStage == SHADERSTAGE_VERTEX)
|
||||
{
|
||||
int nextAttributeIndex = ATTRIB_MAX_ENUM;
|
||||
|
||||
for (const auto &r : shaderResources.stage_inputs)
|
||||
{
|
||||
const auto &name = r.name;
|
||||
const int attributeLocation = static_cast<int>(comp.get_decoration(r.id, spv::DecorationLocation));
|
||||
attributes[name] = attributeLocation;
|
||||
int index;
|
||||
|
||||
BuiltinVertexAttribute builtinAttribute;
|
||||
if (graphics::getConstant(r.name.c_str(), builtinAttribute))
|
||||
index = (int)builtinAttribute;
|
||||
else
|
||||
index = nextAttributeIndex++;
|
||||
|
||||
uint32_t locationOffset;
|
||||
if (!comp.get_binary_offset_for_decoration(r.id, spv::DecorationLocation, locationOffset))
|
||||
throw love::Exception("could not get binary offset for location");
|
||||
|
||||
spirv[locationOffset] = (uint32_t)index;
|
||||
|
||||
attributes[r.name] = index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,6 +955,32 @@ void Shader::compileShaders()
|
||||
|
||||
shaderStages.push_back(shaderStageInfo);
|
||||
}
|
||||
|
||||
numBuffers = 0;
|
||||
numTextures = 0;
|
||||
numBufferViews = 0;
|
||||
|
||||
if (localUniformData.size() > 0)
|
||||
numBuffers++;
|
||||
|
||||
for (const auto &u : uniformInfos)
|
||||
{
|
||||
switch (u.second.baseType)
|
||||
{
|
||||
case UNIFORM_SAMPLER:
|
||||
case UNIFORM_STORAGETEXTURE:
|
||||
numTextures++;
|
||||
break;
|
||||
case UNIFORM_STORAGEBUFFER:
|
||||
numBuffers++;
|
||||
break;
|
||||
case UNIFORM_TEXELBUFFER:
|
||||
numBufferViews++;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::createDescriptorSetLayout()
|
||||
@@ -1085,9 +1068,9 @@ void Shader::createDescriptorPoolSizes()
|
||||
{
|
||||
VkDescriptorPoolSize size{};
|
||||
auto type = Vulkan::getDescriptorType(entry.second.baseType);
|
||||
if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
|
||||
if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
|
||||
continue;
|
||||
}
|
||||
|
||||
size.type = type;
|
||||
size.descriptorCount = 1;
|
||||
descriptorPoolSizes.push_back(size);
|
||||
@@ -1120,7 +1103,8 @@ void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cb
|
||||
if (builtinUniformInfo[builtIns[i]] != nullptr)
|
||||
{
|
||||
textures[i]->retain();
|
||||
builtinUniformInfo[builtIns[i]]->textures[0]->release();
|
||||
if (builtinUniformInfo[builtIns[i]]->textures[0])
|
||||
builtinUniformInfo[builtIns[i]]->textures[0]->release();
|
||||
builtinUniformInfo[builtIns[i]]->textures[0] = textures[i];
|
||||
}
|
||||
}
|
||||
@@ -1136,47 +1120,56 @@ void Shader::setMainTex(graphics::Texture *texture)
|
||||
if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr)
|
||||
{
|
||||
texture->retain();
|
||||
builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release();
|
||||
if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0])
|
||||
builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release();
|
||||
builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::createDescriptorPool()
|
||||
{
|
||||
VkDescriptorPoolCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
createInfo.maxSets = DESCRIPTOR_POOL_SIZE;
|
||||
createInfo.poolSizeCount = static_cast<uint32_t>(descriptorPoolSizes.size());
|
||||
createInfo.pPoolSizes = descriptorPoolSizes.data();
|
||||
|
||||
VkDescriptorPool pool;
|
||||
if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS)
|
||||
throw love::Exception("failed to create descriptor pool");
|
||||
|
||||
descriptorPools[currentFrame].push_back(pool);
|
||||
}
|
||||
|
||||
VkDescriptorSet Shader::allocateDescriptorSet()
|
||||
{
|
||||
if (freeDescriptorSets.empty())
|
||||
if (descriptorPools[currentFrame].empty())
|
||||
createDescriptorPool();
|
||||
|
||||
while (true)
|
||||
{
|
||||
VkDescriptorPoolCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
createInfo.maxSets = DESCRIPTOR_POOL_SIZE;
|
||||
createInfo.poolSizeCount = static_cast<uint32_t>(descriptorPoolSizes.size());
|
||||
createInfo.pPoolSizes = descriptorPoolSizes.data();
|
||||
|
||||
VkDescriptorPool pool;
|
||||
if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS)
|
||||
throw love::Exception("failed to create descriptor pool");
|
||||
descriptorPools.push_back(pool);
|
||||
|
||||
std::vector<VkDescriptorSetLayout> layouts(DESCRIPTOR_POOL_SIZE, descriptorSetLayout);
|
||||
|
||||
VkDescriptorSetAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
allocInfo.descriptorPool = pool;
|
||||
allocInfo.descriptorSetCount = DESCRIPTOR_POOL_SIZE;
|
||||
allocInfo.pSetLayouts = layouts.data();
|
||||
allocInfo.descriptorPool = descriptorPools[currentFrame][currentDescriptorPool];
|
||||
allocInfo.descriptorSetCount = 1;
|
||||
allocInfo.pSetLayouts = &descriptorSetLayout;
|
||||
|
||||
std::vector<VkDescriptorSet> descriptorSet;
|
||||
descriptorSet.resize(DESCRIPTOR_POOL_SIZE);
|
||||
VkResult result = vkAllocateDescriptorSets(device, &allocInfo, descriptorSet.data());
|
||||
if (result != VK_SUCCESS)
|
||||
VkDescriptorSet descriptorSet;
|
||||
VkResult result = vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case VK_SUCCESS:
|
||||
return descriptorSet;
|
||||
case VK_ERROR_OUT_OF_POOL_MEMORY:
|
||||
currentDescriptorPool++;
|
||||
if (descriptorPools[currentFrame].size() <= currentDescriptorPool)
|
||||
createDescriptorPool();
|
||||
continue;
|
||||
default:
|
||||
throw love::Exception("failed to allocate descriptor set");
|
||||
|
||||
for (const auto ds : descriptorSet)
|
||||
freeDescriptorSets.push(ds);
|
||||
}
|
||||
}
|
||||
|
||||
auto ds = freeDescriptorSets.front();
|
||||
freeDescriptorSets.pop();
|
||||
return ds;
|
||||
}
|
||||
|
||||
} // vulkan
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
|
||||
void attach() override;
|
||||
|
||||
ptrdiff_t getHandle() const { return 0; }
|
||||
ptrdiff_t getHandle() const override { return 0; }
|
||||
|
||||
std::string getWarnings() const override { return ""; }
|
||||
|
||||
@@ -97,19 +97,18 @@ private:
|
||||
void createPipelineLayout();
|
||||
void createDescriptorPoolSizes();
|
||||
void createStreamBuffers();
|
||||
void buildLocalUniforms(
|
||||
spirv_cross::Compiler &comp,
|
||||
const spirv_cross::SPIRType &type,
|
||||
size_t baseoff,
|
||||
const std::string &basename);
|
||||
void updateUniform(const UniformInfo *info, int count, bool internal);
|
||||
|
||||
void buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename);
|
||||
void createDescriptorPool();
|
||||
VkDescriptorSet allocateDescriptorSet();
|
||||
|
||||
VkDeviceSize uniformBufferSizeAligned;
|
||||
|
||||
VkPipeline computePipeline;
|
||||
|
||||
uint32_t numTextures;
|
||||
uint32_t numBuffers;
|
||||
uint32_t numBufferViews;
|
||||
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
|
||||
@@ -117,11 +116,7 @@ private:
|
||||
// we don't know how much memory we need per frame for the uniform buffer descriptors
|
||||
// we keep a vector of stream buffers that gets dynamically increased if more memory is needed
|
||||
std::vector<StreamBuffer*> streamBuffers;
|
||||
std::vector<VkDescriptorPool> descriptorPools;
|
||||
std::queue<VkDescriptorSet> freeDescriptorSets;
|
||||
std::vector<std::vector<VkDescriptorSet>> descriptorSetsVector;
|
||||
|
||||
std::set<uint32_t> updatedUniforms;
|
||||
std::vector<std::vector<VkDescriptorPool>> descriptorPools;
|
||||
|
||||
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
||||
std::vector<VkShaderModule> shaderModules;
|
||||
@@ -142,11 +137,9 @@ private:
|
||||
|
||||
std::unordered_map<std::string, int> attributes;
|
||||
|
||||
VkDescriptorSet currentDescriptorSet;
|
||||
|
||||
uint32_t currentFrame;
|
||||
uint32_t currentUsedUniformStreamBuffersCount;
|
||||
uint32_t currentUsedDescriptorSetsCount;
|
||||
uint32_t currentDescriptorPool;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -747,8 +747,54 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type)
|
||||
}
|
||||
}
|
||||
|
||||
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout,
|
||||
uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
|
||||
static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags, bool &depthStencil)
|
||||
{
|
||||
switch (layout)
|
||||
{
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
accessMask = 0;
|
||||
if (previous)
|
||||
stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
else
|
||||
stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
// We use the general image layout for images that are both compute write and readable.
|
||||
// todo: can we optimize this?
|
||||
accessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
|
||||
stageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
stageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
depthStencil = true;
|
||||
accessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||
stageFlags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
accessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
accessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
accessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
|
||||
accessMask = 0;
|
||||
stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
break;
|
||||
default:
|
||||
throw love::Exception("unimplemented image layout");
|
||||
}
|
||||
}
|
||||
|
||||
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
|
||||
{
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
@@ -757,176 +803,22 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.baseMipLevel = baseLevel;
|
||||
barrier.subresourceRange.levelCount = levelCount;
|
||||
barrier.subresourceRange.baseArrayLayer = baseLayer;
|
||||
barrier.subresourceRange.layerCount = layerCount;
|
||||
|
||||
bool depthStencil = false;
|
||||
VkPipelineStageFlags sourceStage;
|
||||
VkPipelineStageFlags destinationStage;
|
||||
|
||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage, depthStencil);
|
||||
setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage, depthStencil);
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.dstAccessMask = 0;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
}
|
||||
// we use general for images that are both sampled and compute write
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL)
|
||||
{
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
|
||||
{
|
||||
if (depthStencil)
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
{
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
|
||||
{
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barrier.dstAccessMask = 0;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_UNDEFINED)
|
||||
{
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
barrier.dstAccessMask = 0;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
}
|
||||
else
|
||||
throw std::invalid_argument("unsupported layout transition!");
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
|
||||
Reference in New Issue
Block a user